1111from datetime import datetime
1212from copy import deepcopy
1313from threading import Lock
14+ # from uuid import uuid4
1415import os .path
1516import shutil
17+ import time
1618
1719from helpermodules .utils .error_handling import ImportErrorContext
1820with ImportErrorContext ():
2123 from bimmer_connected .account import MyBMWAccount
2224 from bimmer_connected .api .regions import Regions
2325 from bimmer_connected .utils import MyBMWJSONEncoder
26+ from bimmer_connected .models import MyBMWAPIError
2427
2528from modules .common .component_state import CarState
2629from modules .common .store import RAMDISK_PATH
@@ -205,13 +208,15 @@ async def _fetch_soc(self,
205208 if self ._store [user_id ]['captcha_token' ] != captcha_token :
206209 # invalidate current refresh and access token to force new login
207210 log .debug ("new captcha token configured - invalidate stored token set" )
211+ self ._new_captcha = True
208212 self ._store [user_id ]['expires_at' ] = None
209213 self ._store [user_id ]['access_token' ] = None
210214 self ._store [user_id ]['refresh_token' ] = None
211215 self ._store [user_id ]['session_id' ] = None
212216 self ._store [user_id ]['gcid' ] = None
213217 else :
214218 log .debug ("captcha token unchanged" )
219+ self ._new_captcha = False
215220
216221 if user_id not in self ._auth :
217222 if self ._store [user_id ]['expires_at' ] is not None and \
@@ -227,7 +232,8 @@ async def _fetch_soc(self,
227232 Regions .REST_OF_WORLD ,
228233 refresh_token = self ._store [user_id ]['refresh_token' ],
229234 access_token = self ._store [user_id ]['access_token' ],
230- expires_at = expires_at )
235+ expires_at = expires_at ,
236+ hcaptcha_token = captcha_token )
231237 else :
232238 # no token, authenticate via user_id, password and captcha_token
233239 log .info ("authenticate via userid, password, captcha token" )
@@ -252,7 +258,7 @@ async def _fetch_soc(self,
252258 else :
253259 log .debug ("# Reuse _clconf instance" )
254260
255- # instantiate account object of not existent yet
261+ # instantiate account object if not existent yet
256262 if user_id not in self ._account :
257263 log .debug ("# Create _account instance" )
258264 # user, password and region already set in BMWAuthentication/ClientConfiguration!
@@ -273,6 +279,7 @@ async def _fetch_soc(self,
273279 if user_id not in self ._last_reload :
274280 self ._last_reload [user_id ] = 0
275281 if self ._now > self ._last_reload [user_id ] + 5 * 60 :
282+ # self._auth[user_id].session_id = str(uuid4()) # experimental to avoid error 408: reset session_id
276283 # experimental: login when expires_at is reached to force token refresh
277284 if self ._store [user_id ]['expires_at' ] is not None :
278285 expires_at = datetime .fromisoformat (self ._store [user_id ]['expires_at' ])
@@ -287,9 +294,36 @@ async def _fetch_soc(self,
287294 "/" + self ._auth [user_id ].refresh_token )
288295
289296 # get vehicle list - needs to be called async
290- log .info (self ._mode + ": reload vehicles data" )
291- await self ._account [user_id ].get_vehicles ()
292- self ._last_reload [user_id ] = datetime .timestamp (datetime .now ())
297+ _loop = 5 # 5 retries
298+ while _loop > 0 :
299+ log .info (self ._mode + ": reload vehicles data/" + str (_loop ))
300+ try :
301+ await self ._account [user_id ].get_vehicles ()
302+ except MyBMWAPIError as err :
303+ log .info (self ._mode + ": get_vehicles err= " + str (err .__class__ ) + ": " + str (err ))
304+ _err = - 1
305+ if 'Internal Server Error' in str (err ):
306+ log .info (self ._mode + ": get_vehicles : Internal Server Error" )
307+ _err = 500
308+ if 'Request Timeout' in str (err ):
309+ log .info (self ._mode + ": get_vehicles : Request Timeout" )
310+ _err = 408
311+ log .info (self ._mode + ": get_vehicles : _err=" + str (_err ))
312+ time .sleep (10 ) # experimental: sleep for 10 secs
313+ # log.info(self._mode + ": get_vehicles exception " + str(err))
314+ log .info ("# before except login:" + str (self ._auth [user_id ].expires_at ) +
315+ "/" + self ._auth [user_id ].refresh_token )
316+ await self ._auth [user_id ].login ()
317+ log .info ("# after except login:" + str (self ._auth [user_id ].expires_at ) +
318+ "/" + self ._auth [user_id ].refresh_token )
319+ await self ._account [user_id ].get_vehicles ()
320+ _loop = _loop - 1
321+ except Exception as err :
322+ log .error ("bmwbc.fetch_soc: get_vehicles Error, vehicle_id: " +
323+ vehicle_id + f" { err = } , { type (err )= } " )
324+ raise err
325+ self ._last_reload [user_id ] = datetime .timestamp (datetime .now ())
326+ _loop = 0
293327
294328 # get vehicle data for vin
295329 vehicle = self ._account [user_id ].get_vehicle (vin )
@@ -305,9 +339,15 @@ async def _fetch_soc(self,
305339 soc = int (state ['electricChargingState' ]['chargingLevelPercent' ])
306340 range = float (state ['electricChargingState' ]['range' ])
307341 lastUpdatedAt = state ['lastUpdatedAt' ]
308- # convert lastUpdatedAt to soc_timestamp
309- soc_tsdtZ = datetime .strptime (lastUpdatedAt , ts_fmt + "Z" )
310- soc_tsX = datetime .timestamp (soc_tsdtZ )
342+ if self ._new_captcha :
343+ # after new captcha use system timestamp
344+ # soc_tsX = datetime.timestamp(datetime.now())
345+ # after new captcha use timestamp 0 (19700101)
346+ soc_tsX = 0
347+ else :
348+ # convert lastUpdatedAt to soc_timestamp
349+ soc_tsdtZ = datetime .strptime (lastUpdatedAt , ts_fmt + "Z" )
350+ soc_tsX = datetime .timestamp (soc_tsdtZ )
311351
312352 # save the vehicle data for further analysis if required
313353 dump_json (respd , replyFilePrefix + vehicle_id )
@@ -333,15 +373,17 @@ async def _fetch_soc(self,
333373 "/" + self ._auth [user_id ].refresh_token )
334374
335375 except Exception as err :
336- log .error ("bmwbc.fetch_soc: requestData Error, vehicle_id: " + vehicle_id + f" { err = } , { type (err )= } " )
376+ # log.error("bmwbc.fetch_soc: requestData Error, vehicle_id: " + vehicle_id + f" {err=}, {type(err)=}")
377+ log .error ("bmwbc.fetch_soc: requestData Error, vehicle_id: " + str (vehicle_id ))
337378 # self._auth = None
338379 self ._auth .pop (user_id , None )
339380 self ._clconf .pop (user_id , None )
340381 self ._account .pop (user_id , None )
341382 soc = 0
342383 range = 0.0
343384 soc_tsX = datetime .timestamp (datetime .now ())
344- raise RequestFailed ("SoC Request failed:\n " + str (err ))
385+ # raise RequestFailed("SoC Request failed:\n" + str(err))
386+ raise Exception ("SoC Request failed" ) from err
345387 return soc , range , soc_tsX
346388
347389
0 commit comments