From 3ac6cab14718867896cc883a70c4c7d42974a9b7 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 26 Dec 2019 13:13:14 -0500 Subject: [PATCH 1/3] Refactor API error handling Use a declarative style for mapping errors. Also add a new one for an "invalid request" message. --- wideq/core.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/wideq/core.py b/wideq/core.py index da868b0..ef8927e 100644 --- a/wideq/core.py +++ b/wideq/core.py @@ -85,6 +85,13 @@ class TokenError(APIError): pass +class InvalidRequestError(APIError): + """The server rejected a request as invalid.""" + + def __init__(self): + pass + + class MonitorError(APIError): """Monitoring a device failed, possibly because the monitoring session failed and needs to be restarted. @@ -95,6 +102,13 @@ class MonitorError(APIError): self.code = code +API_ERRORS = { + "0102": NotLoggedInError, + "0106": NotConnectedError, + 9000: InvalidRequestError, # Surprisingly, an integer (not a string). +} + + def lgedm_post(url, data=None, access_token=None, session_id=None): """Make an HTTP request in the format used by the API servers. @@ -123,14 +137,13 @@ def lgedm_post(url, data=None, access_token=None, session_id=None): # Check for API errors. if 'returnCd' in out: code = out['returnCd'] - if code != '0000': + if code == '0000': + pass + elif code in API_ERRORS: + raise API_ERRORS[code]() + else: message = out['returnMsg'] - if code == "0102": - raise NotLoggedInError() - elif code == "0106": - raise NotConnectedError() - else: - raise APIError(code, message) + raise APIError(code, message) return out From dbab3fd1fec981635fe4b1ea61774b1d3a603c69 Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 26 Dec 2019 13:33:25 -0500 Subject: [PATCH 2/3] Do not crash on failed speaker volume retrieval Fixes #63. --- wideq/ac.py | 8 ++++++-- wideq/core.py | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/wideq/ac.py b/wideq/ac.py index e6a2c7e..c2c8848 100644 --- a/wideq/ac.py +++ b/wideq/ac.py @@ -3,6 +3,7 @@ import enum from .client import Device +from .core import FailedRequestError class ACVSwingMode(enum.Enum): @@ -256,8 +257,11 @@ class ACDevice(Device): def get_volume(self): """Get the speaker volume level.""" - value = self._get_control('SpkVolume') - return int(value) + try: + value = self._get_control('SpkVolume') + return int(value) + except FailedRequestError: + return 0 # Device does not support volume control. def poll(self): """Poll the device's current state. diff --git a/wideq/core.py b/wideq/core.py index ef8927e..df31a2c 100644 --- a/wideq/core.py +++ b/wideq/core.py @@ -85,6 +85,15 @@ class TokenError(APIError): pass +class FailedRequestError(APIError): + """A failed request typically indicates an unsupported control on a + device. + """ + + def __init__(self): + pass + + class InvalidRequestError(APIError): """The server rejected a request as invalid.""" @@ -105,6 +114,7 @@ class MonitorError(APIError): API_ERRORS = { "0102": NotLoggedInError, "0106": NotConnectedError, + "0100": FailedRequestError, 9000: InvalidRequestError, # Surprisingly, an integer (not a string). } From 47765d21e41bac0989144f4ce64cf960b795808c Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Thu, 26 Dec 2019 13:35:53 -0500 Subject: [PATCH 3/3] Preserve codes for named errors This simplifies the definition of error classes *and* preserves more information about the underlying message from the API. --- wideq/core.py | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/wideq/core.py b/wideq/core.py index df31a2c..993ca62 100644 --- a/wideq/core.py +++ b/wideq/core.py @@ -67,16 +67,10 @@ class APIError(Exception): class NotLoggedInError(APIError): """The session is not valid or expired.""" - def __init__(self): - pass - class NotConnectedError(APIError): """The service can't contact the specified device.""" - def __init__(self): - pass - class TokenError(APIError): """An authentication token was rejected.""" @@ -90,16 +84,10 @@ class FailedRequestError(APIError): device. """ - def __init__(self): - pass - class InvalidRequestError(APIError): """The server rejected a request as invalid.""" - def __init__(self): - pass - class MonitorError(APIError): """Monitoring a device failed, possibly because the monitoring @@ -147,13 +135,12 @@ def lgedm_post(url, data=None, access_token=None, session_id=None): # Check for API errors. if 'returnCd' in out: code = out['returnCd'] - if code == '0000': - pass - elif code in API_ERRORS: - raise API_ERRORS[code]() - else: + if code != '0000': message = out['returnMsg'] - raise APIError(code, message) + if code in API_ERRORS: + raise API_ERRORS[code](code, message) + else: + raise APIError(code, message) return out