diff --git a/teslajsonpy/car.py b/teslajsonpy/car.py index 71fa82aa..3e385c2d 100644 --- a/teslajsonpy/car.py +++ b/teslajsonpy/car.py @@ -987,8 +987,7 @@ async def remote_auto_steering_wheel_heat_climate_request( """ data = await self._send_command( - "REMOTE_AUTO_STEERING_WHEEL_HEAT_CLIMATE_REQUEST", - on=enable + "REMOTE_AUTO_STEERING_WHEEL_HEAT_CLIMATE_REQUEST", on=enable ) if data and data["response"]["result"] is True: params = {"auto_steering_wheel_heat": enable} @@ -1017,7 +1016,9 @@ async def set_heated_steering_wheel_level(self, level: int) -> None: def get_heated_steering_wheel_level(self) -> int: """Return the status of the heated steering wheel.""" if self.data_available: - return self._vehicle_data.get("climate_state", {}).get("steering_wheel_heat_level") + return self._vehicle_data.get("climate_state", {}).get( + "steering_wheel_heat_level" + ) return None async def set_hvac_mode(self, value: str) -> None: diff --git a/teslajsonpy/controller.py b/teslajsonpy/controller.py index 231aca56..baaa7df8 100644 --- a/teslajsonpy/controller.py +++ b/teslajsonpy/controller.py @@ -33,7 +33,12 @@ WAKE_TIMEOUT, ) from teslajsonpy.energy import EnergySite, PowerwallSite, SolarPowerwallSite, SolarSite -from teslajsonpy.exceptions import TeslaException, custom_retry, custom_wait +from teslajsonpy.exceptions import ( + TeslaException, + custom_retry, + custom_retry_except_unavailable, + custom_wait, +) _LOGGER = logging.getLogger(__name__) @@ -743,7 +748,11 @@ async def _get_and_process_battery_summary( cur_time - last_update, ONLINE_INTERVAL, ) - if force or cur_time - last_update >= ONLINE_INTERVAL and update_vehicles: + if ( + force + or cur_time - last_update >= ONLINE_INTERVAL + and update_vehicles + ): cars = await self.get_vehicles() for car in cars: self.set_id_vin(car_id=car["id"], vin=car["vin"]) @@ -1333,7 +1342,11 @@ async def api( return response # Perform request using given keyword arguments as parameters - return await self.__post_with_retries("", method=method, data=kwargs, url=uri) + # wake_if_asleep is False so we do not retry if the car is asleep + # or if the car is unavailable + return await self.__post_with_retries_except_unavailable( + "", method=method, data=kwargs, url=uri + ) @retry( wait=custom_wait, @@ -1342,5 +1355,25 @@ async def api( reraise=True, ) async def __post_with_retries(self, command, method="post", data=None, url=""): - """Call connection.post with retries for common exceptions.""" + """Call connection.post with retries for common exceptions. + + Retries if the car is unavailable. + """ + return await self.__connection.post(command, method=method, data=data, url=url) + + @retry( + wait=custom_wait, + retry=custom_retry_except_unavailable, + stop=stop_after_delay(MAX_API_RETRY_TIME), + reraise=True, + ) + async def __post_with_retries_except_unavailable( + self, command, method="post", data=None, url="" + ): + """Call connection.post with retries for common exceptions. + + Does not retry if the car is unavailable. This should be + used when wake_if_asleep is False since its unlikely the + car will suddenly become available if its offline/sleep. + """ return await self.__connection.post(command, method=method, data=data, url=url) diff --git a/teslajsonpy/exceptions.py b/teslajsonpy/exceptions.py index e159f0a5..6a4e08a8 100644 --- a/teslajsonpy/exceptions.py +++ b/teslajsonpy/exceptions.py @@ -82,6 +82,25 @@ class HomelinkError(TeslaException): pass +def custom_retry_except_unavailable(retry_state: RetryCallState) -> bool: + """Determine whether Tenacity should retry. + + Args + retry_state (RetryCallState): Provided by Tenacity + + Returns + bool: whether or not to retry + + """ + if not custom_retry(retry_state): + return False + ex = retry_state.outcome.exception() + if isinstance(ex, TeslaException): + if ex.code == 408: # "VEHICLE_UNAVAILABLE" + return False + return True + + def custom_retry(retry_state: RetryCallState) -> bool: """Determine whether Tenacity should retry.