Skip to content

Commit

Permalink
Added missing V2 states
Browse files Browse the repository at this point in the history
- Added missing V2 states
- Set Auth v2 as default
  • Loading branch information
ollo69 committed Apr 8, 2020
1 parent 4e9676c commit 2b22aa3
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 59 deletions.
12 changes: 6 additions & 6 deletions custom_components/smartthinq_washer/.translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
"data": {
"region": "Region (e.g. US)",
"language": "Language (e.g. en-US)",
"token": "Access Token (only for API v1)",
"use_api_v2": "Use API v2 (experimental)"
"token": "Refresh Token (only for Authentication mode v1)",
"use_api_v2": "Use Authentication mode v2"
},
"description": "Fill in your SmartThinQ access information. If you don't have an access token, leave it empty to start the process for generating a new one.",
"description": "Fill in your SmartThinQ access information. If you don't have a refresh token, leave it empty to start the authentication process with your credentials. Refresh token is not used with Authentication mode v2.",
"title": "SmartThinQ LGE Washer"
},
"url": {
Expand All @@ -27,14 +27,14 @@
"callback_url": "Redirection URL"
},
"description": "Use the URL in the first field to perform login to SmartThinQ with your credentials, then paste the URL where the browser is redirected after the login in the second field.",
"title": "SmartThinQ LGE Washer - Token generation"
"title": "SmartThinQ LGE Washer - Authentication"
},
"token": {
"data": {
"token": "Access Token"
"token": "Refresh Token"
},
"description": "Save the generated token for future use, then confirm to complete the configuration.",
"title": "SmartThinQ LGE Washer - New token"
"title": "SmartThinQ LGE Washer - New refresh token"
}
},
"title": "SmartThinQ LGE Washer"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/smartthinq_washer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

class LGEAuthentication:

def __init__(self, region, language, use_api_v2=False):
def __init__(self, region, language, use_api_v2=True):
self._region = region
self._language = language
self._use_api_v2 = use_api_v2
Expand Down
4 changes: 2 additions & 2 deletions custom_components/smartthinq_washer/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
vol.Required(CONF_REGION): str,
vol.Required(CONF_LANGUAGE): str,
vol.Optional(CONF_TOKEN): str,
vol.Required(CONF_USE_API_V2, default=False): bool,
vol.Required(CONF_USE_API_V2, default=True): bool,
})

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -129,7 +129,7 @@ async def async_step_user(self, user_input=None):
region = user_input[CONF_REGION]
language = user_input[CONF_LANGUAGE]
refresh_token = user_input.get(CONF_TOKEN, "")
self._use_api_v2 = user_input[CONF_USE_API_V2]
self._use_api_v2 = user_input.get(CONF_USE_API_V2, False)

if self._use_api_v2:
refresh_token = ""
Expand Down
87 changes: 65 additions & 22 deletions custom_components/smartthinq_washer/wideq/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
STATE_OPTIONITEM_OFF = "Off"
STATE_OPTIONITEM_UNKNOWN = "unknown"

BIT_OFF_THINQ2 = "@CP_OFF_EN_W"
BIT_ON_THINQ2 = "@CP_ON_EN_W"

OPTIONITEMMODES = {
"ON": STATE_OPTIONITEM_ON,
"OFF": STATE_OPTIONITEM_OFF,
Expand Down Expand Up @@ -237,6 +240,7 @@ class ModelInfo(object):

def __init__(self, data):
self.data = data
self.is_api_v2 = False

@property
def model_type(self):
Expand Down Expand Up @@ -383,27 +387,38 @@ class ModelInfoV2(object):

def __init__(self, data):
self.data = data
self.is_api_v2 = True

@property
def model_type(self):
return self.data['Info']['modelType']

def value_type(self, name):
return None

def data_root(self, name):
if name in self.data['MonitoringValue']:
return self.data['MonitoringValue'][name]['dataType']
else:
return None
if self.data['MonitoringValue'][name].get('dataType'):
return self.data['MonitoringValue'][name]
else:
ref = self.data['MonitoringValue'][name].get('ref')
if ref:
return self.data.get(ref)

def value(self, name):
return None

def value(self, data):
"""Look up information about a value.
Return either an `EnumValue` or a `RangeValue`.
"""
d = self.data['MonitoringValue'][name]
if d['dataType'] in ('Enum', 'enum'):
return d['valueMapping']
elif d['dataType'] == 'range':
return RangeValue(d['valueMapping']['min'], d['valueMapping']['max'])
data_type = data.get('dataType')
if not data_type:
return data
elif data_type in ('Enum', 'enum'):
return data['valueMapping']
elif data_type == 'range':
return RangeValue(data['valueMapping']['min'], data['valueMapping']['max'])
#elif d['dataType'] == 'Bit':
# bit_values = {}
# for bit in d['option']:
Expand Down Expand Up @@ -436,38 +451,57 @@ def default(self, name):
def enum_value(self, key, name):
"""Look up the encoded value for a friendly enum name.
"""
data = self.data_root(key)
if not data:
return str(name)

options = self.value(key)
options = self.value(data)
options_inv = {v: k for k, v in options.items()} # Invert the map.
return options_inv[name]

def enum_name(self, key, value):
"""Look up the friendly enum name for an encoded value.
"""
if not self.value_type(key):
data = self.data_root(key)
if not data:
return str(value)

options = self.value(key)
options = self.value(data)
return options[value]["label"]

def range_name(self, key):
"""Look up the value of a RangeValue. Not very useful other than for comprehension
"""
return key

def bit_name(self, key, bit_index, value):
"""Look up the friendly name for an encoded bit value
"""
return str(value)
return None

def bit_name_v2(self, key, value):
"""Look up the friendly name for an encoded bit value
"""
data = self.data_root(key)
if not data:
return None

bit_val = self.value(data)[value]["label"]
if bit_val == BIT_OFF_THINQ2:
return False
elif bit_val == BIT_ON_THINQ2:
return True

return None

def reference_name(self, key, value):
"""Look up the friendly name for an encoded reference value
"""
value = str(value)
if not self.value_type(key):
return value
data = self.data_root(key)
if not data:
return str(value)

reference = self.value(key)
reference = self.value(data)

if value in reference:
comment = reference[value].get('_comment')
Expand All @@ -480,7 +514,7 @@ def binary_monitor_data(self):
"""Check that type of monitoring is BINARY(BYTE).
"""

return self.data['Monitoring']['type'] == 'BINARY(BYTE)'
return False

def decode_monitor_binary(self, data):
"""Decode binary encoded status data.
Expand Down Expand Up @@ -533,8 +567,7 @@ def __init__(self, client, device):
else:
self.model = ModelInfo(model_data)
self._should_poll = (device.platform_type == PlatformType.THINQ1)
#self._should_poll = False


# for logging unknown states received
self._unknown_states = []

Expand Down Expand Up @@ -642,6 +675,7 @@ class DeviceStatus(object):
def __init__(self, device, data):
self.device = device
self.data = data
self.is_api_v2 = device.model.is_api_v2

def _get_data_key(self, keys):
if isinstance(keys, list):
Expand Down Expand Up @@ -685,3 +719,12 @@ def lookup_bit(self, key, index):
return 'OFF'
else:
return 'ON'

def lookup_bit_v2(self, key):
curr_key = self._get_data_key(key)
if not curr_key:
return STATE_OPTIONITEM_UNKNOWN
result = self.device.model.bit_name_v2(curr_key, self.data[curr_key])
if result is None:
return STATE_OPTIONITEM_UNKNOWN
return 'ON' if result else 'OFF'
68 changes: 40 additions & 28 deletions custom_components/smartthinq_washer/wideq/washer.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,93 +125,105 @@ def water_temp_option_state(self):

@property
def current_course(self):
course = self.lookup_reference(['APCourse', 'Course'])
course = self.lookup_reference(['APCourse', 'Course', 'courseFL24inchBaseTitan'])
if course == '-':
return 'OFF'
return course

@property
def current_smartcourse(self):
smartcourse = self.lookup_reference('SmartCourse')
smartcourse = self.lookup_reference(['SmartCourse', 'smartCourseFL24inchBaseTitan'])
if smartcourse == '-':
return 'OFF'
else:
return smartcourse

@property
def remaintime_hour(self):
value = self.data.get('Remain_Time_H')
if not value:
value = str(int(self.data.get('remainTimeHour')))
return value

if self.is_api_v2:
return str(int(self.data.get('remainTimeHour')))
return self.data.get('Remain_Time_H')

@property
def remaintime_min(self):
value = self.data.get('Remain_Time_M')
if not value:
value = str(int(self.data.get('remainTimeMinute')))
return value
if self.is_api_v2:
return str(int(self.data.get('remainTimeMinute')))
return self.data.get('Remain_Time_M')

@property
def initialtime_hour(self):
value = self.data.get('Initial_Time_H')
if not value:
value = str(int(self.data.get('initialTimeHour')))
return value
if self.is_api_v2:
return str(int(self.data.get('initialTimeHour')))
return self.data.get('Initial_Time_H')

@property
def initialtime_min(self):
value = self.data.get('Initial_Time_M')
if not value:
value = str(int(self.data.get('initialTimeMinute')))
return value
if self.is_api_v2:
return str(int(self.data.get('initialTimeMinute')))
return self.data.get('Initial_Time_M')

@property
def reservetime_hour(self):
value = self.data.get('Reserve_Time_H')
if not value:
value = str(int(self.data.get('reserveTimeHour')))
return value
if self.is_api_v2:
return str(int(self.data.get('reserveTimeHour')))
return self.data.get('Reserve_Time_H')

@property
def reservetime_min(self):
value = self.data.get('Reserve_Time_M')
if not value:
value = str(int(self.data.get('reserveTimeMinute')))
return value
if self.is_api_v2:
return str(int(self.data.get('reserveTimeMinute')))
return self.data.get('Reserve_Time_M')

@property
def creasecare_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('creaseCare')
return self.lookup_bit('Option1', 1)

@property
def childlock_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('childLock')
return self.lookup_bit('Option2', 7)

@property
def steam_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('steam')
return self.lookup_bit('Option1', 7)

@property
def steam_softener_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('steamSoftener')
return self.lookup_bit('Option1', 2)

@property
def doorlock_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('doorLock')
return self.lookup_bit('Option2', 6)

@property
def prewash_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('preWash')
return self.lookup_bit('Option1', 6)

@property
def remotestart_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('remoteStart')
return self.lookup_bit('Option2', 1)

@property
def turbowash_state(self):
if self.is_api_v2:
return self.lookup_bit_v2('turboWash')
return self.lookup_bit('Option1', 0)

@property
def tubclean_count(self):
return self.data['TCLCount']
if self.is_api_v2:
return str(int(self.data.get('TCLCount', -1)))
return self.data.get('TCLCount')

0 comments on commit 2b22aa3

Please sign in to comment.