Skip to content

Commit

Permalink
Various rate-limiting handling (#33)
Browse files Browse the repository at this point in the history
  • Loading branch information
bm1549 authored Jun 29, 2024
1 parent 9d9f321 commit 994fb54
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
33 changes: 25 additions & 8 deletions frigidaire/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Frigidaire 2.0 API client"""
import traceback
from enum import Enum
from requests import Response
from typing import Optional, Dict, Union, List
Expand Down Expand Up @@ -428,7 +429,12 @@ def get_appliances_inner():

try:
return get_appliances_inner()
except FrigidaireException:
except FrigidaireException as e:
# Re-authenticating on a 429 makes things worse
if "cas_3403" in traceback.format_exc():
logging.debug("Rate limited - try again later")
raise e

logging.debug('Listing appliances failed - attempting to re-authenticate')
self.re_authenticate()
return get_appliances_inner()
Expand All @@ -446,7 +452,12 @@ def get_appliance_details(self, appliance: Appliance) -> Dict:
appliances = self.get_request(self.regional_base_url,
'/appliance/api/v2/appliances?includeMetadata=true',
self.get_headers_frigidaire("GET", include_bearer_token=True))
except FrigidaireException:
except FrigidaireException as e:
# Re-authenticating on a 429 makes things worse
if "cas_3403" in traceback.format_exc():
logging.debug("Rate limited - try again later")
raise e

self.re_authenticate()
appliances = self.get_request(self.regional_base_url,
'/appliance/api/v2/appliances?includeMetadata=true',
Expand Down Expand Up @@ -475,7 +486,12 @@ def execute_action(self, appliance: Appliance, action: List[Component]) -> None:
self.put_request(self.regional_base_url,
f'/appliance/api/v2/appliances/{appliance.appliance_id}/command',
self.get_headers_frigidaire("PUT", include_bearer_token=True), data)
except FrigidaireException:
except FrigidaireException as e:
# Re-authenticating on a 429 makes things worse
if "cas_3403" in traceback.format_exc():
logging.debug("Rate limited - try again later")
raise e

self.re_authenticate()
self.put_request(self.regional_base_url,
f'/appliance/api/v2/appliances/{appliance.appliance_id}/command',
Expand All @@ -493,28 +509,29 @@ def parse_response(response: Response) -> Dict:

try:
if response.headers.get('Content-Encoding') == 'gzip':
# Hack: Sometimes the server indicates "Content-Encoding: gzip" but does not send gzipped data
# Hack: Often, the server indicates "Content-Encoding: gzip" but does not send gzipped data
try:
data = gzip.decompress(response.content)
response_dict = json.loads(data.decode("utf-8"))
except gzip.BadGzipFile:
logging.debug("Bad gzipped payload-- attempting to parse as plaintext")
response_dict = response.json()
elif response.content == b'':
# The server says it was JSON, but it was not
response_dict = {}
else:
response_dict = response.json()
except Exception as e:
logging.error(e)
raise FrigidaireException(f'Received an unexpected response:\n{response.content}')
raise FrigidaireException(f'Received an unexpected response:\n{response.content}') from e

return response_dict

@staticmethod
def handle_request_exception(e: Exception, method: str, fullpath: str, headers: Dict[str, str], payload: str):
logging.warning(e)
error_str = f'Error processing request:\n{method} {fullpath}\nheaders={headers}\npayload={payload}\n'
'This may be safely ignored when used to test for a good connection in the authentication flow'
logging.warning(error_str)
raise FrigidaireException(error_str)
raise FrigidaireException(error_str) from e

def get_request(self, url: str, path: str, headers: Dict[str, str]) -> Union[Dict, List]:
"""
Expand Down
19 changes: 16 additions & 3 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
# You can use the following contents as a starting point
"""
[credentials]
[email protected]
Password=password
[email protected]
password=password
; session_key=insert_session_key_here
; regional_base_url=https://api.us.ocp.electrolux.one
"""
config = configparser.ConfigParser()
config.read('config.ini')
Expand All @@ -20,40 +22,51 @@
username = credentials.get('username')
password = credentials.get('password')
session_key = credentials.get('session_key', fallback=None)
regional_base_url = credentials.get('regional_base_url', fallback=None)

frigidaire = Frigidaire(
username,
password,
# session_key, # uncomment this if testing with an already authenticated session key
session_key=session_key,
regional_base_url=regional_base_url,
# timeout=5, # uncomment this if testing the request timeout
)

# tests connectivity
logging.debug("tests connectivity")
frigidaire.test_connection()

# get appliances
logging.debug("get appliance")
appliances = frigidaire.get_appliances()

# pick one arbitrarily
appliance = appliances[0]

# get some details for it
logging.debug("get details")
appliance_details = frigidaire.get_appliance_details(appliance)

# turn on
logging.debug("turn on")
frigidaire.execute_action(appliance, Action.set_power(Power.ON))

# set to cool
logging.debug("set to cool")
frigidaire.execute_action(appliance, Action.set_mode(Mode.COOL))

# set fan to medium
logging.debug("set fan to medium")
frigidaire.execute_action(appliance, Action.set_fan_speed(FanSpeed.MEDIUM))

# set temperature to 75
logging.debug("set temp to 75")
frigidaire.execute_action(appliance, Action.set_temperature(75))

# re-authenticate the connection to get a new session_key
logging.debug("re-authenticate")
frigidaire.re_authenticate()

# turn off
logging.debug("turn off")
frigidaire.execute_action(appliance, Action.set_power(Power.OFF))

0 comments on commit 994fb54

Please sign in to comment.