From ee52706f03fdcdd9e8485a22df3257c0528cf133 Mon Sep 17 00:00:00 2001 From: bwduncan Date: Mon, 12 Jul 2021 19:57:08 +0100 Subject: [PATCH] Poll Nissan servers for battery updates (#44826) --- .../components/nissan_leaf/__init__.py | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/nissan_leaf/__init__.py b/homeassistant/components/nissan_leaf/__init__.py index 24adf223719..a0a39542a20 100644 --- a/homeassistant/components/nissan_leaf/__init__.py +++ b/homeassistant/components/nissan_leaf/__init__.py @@ -45,7 +45,7 @@ DEFAULT_CLIMATE_INTERVAL = timedelta(minutes=5) RESTRICTED_BATTERY = 2 RESTRICTED_INTERVAL = timedelta(hours=12) -MAX_RESPONSE_ATTEMPTS = 10 +MAX_RESPONSE_ATTEMPTS = 3 PYCARWINGS2_SLEEP = 30 @@ -194,6 +194,14 @@ def setup(hass, config): return True +def _extract_start_date(battery_info): + """Extract the server date from the battery response.""" + try: + return battery_info.answer["BatteryStatusRecords"]["OperationDateAndTime"] + except KeyError: + return None + + class LeafDataStore: """Nissan Leaf Data Store.""" @@ -324,19 +332,24 @@ class LeafDataStore: self.request_in_progress = False async_dispatcher_send(self.hass, SIGNAL_UPDATE_LEAF) - @staticmethod - def _extract_start_date(battery_info): - """Extract the server date from the battery response.""" - try: - return battery_info.answer["BatteryStatusRecords"]["OperationDateAndTime"] - except KeyError: - return None - async def async_get_battery(self): """Request battery update from Nissan servers.""" try: # Request battery update from the car _LOGGER.debug("Requesting battery update, %s", self.leaf.vin) + start_date = None + try: + start_server_info = await self.hass.async_add_executor_job( + self.leaf.get_latest_battery_status + ) + except TypeError: # pycarwings2 can fail if Nissan returns nothing + _LOGGER.debug("Battery status check returned nothing") + else: + if not start_server_info: + _LOGGER.debug("Battery status check failed") + else: + start_date = _extract_start_date(start_server_info) + await asyncio.sleep(1) # Critical sleep request = await self.hass.async_add_executor_job(self.leaf.request_update) if not request: _LOGGER.error("Battery update request failed") @@ -364,7 +377,19 @@ class LeafDataStore: server_info = await self.hass.async_add_executor_job( self.leaf.get_latest_battery_status ) - return server_info + if not start_date or ( + server_info and start_date != _extract_start_date(server_info) + ): + return server_info + # get_status_from_update returned {"resultFlag": "1"} + # but the data didn't change, make a fresh request. + await asyncio.sleep(1) # Critical sleep + request = await self.hass.async_add_executor_job( + self.leaf.request_update + ) + if not request: + _LOGGER.error("Battery update request failed") + return None _LOGGER.debug( "%s attempts exceeded return latest data from server", @@ -379,7 +404,7 @@ class LeafDataStore: except CarwingsError: _LOGGER.error("An error occurred getting battery status") return None - except KeyError: + except (KeyError, TypeError): _LOGGER.error("An error occurred parsing response from server") return None