pycupra 0.1.4__py3-none-any.whl → 0.1.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pycupra/dashboard.py CHANGED
@@ -453,6 +453,7 @@ class RequestRefresh(Switch):
453
453
  return self.vehicle.refresh_data
454
454
 
455
455
  async def turn_on(self):
456
+ _LOGGER.debug('User has called RequestRefresh().')
456
457
  await self.vehicle.set_refresh()
457
458
  await self.vehicle.update(updateType=1) #full update after set_refresh
458
459
  if self.callback is not None:
@@ -479,6 +480,7 @@ class RequestUpdate(Switch):
479
480
  return False #self.vehicle.update
480
481
 
481
482
  async def turn_on(self):
483
+ _LOGGER.debug('User has called RequestUpdate().')
482
484
  await self.vehicle.update(updateType=1) #full update after set_refresh
483
485
  if self.callback is not None:
484
486
  self.callback()
pycupra/firebase.py CHANGED
@@ -16,29 +16,46 @@ from .const import (
16
16
  _LOGGER = logging.getLogger(__name__)
17
17
 
18
18
  class Firebase():
19
+ def __init__(self):
20
+ self._pushClient = None
21
+
19
22
  async def firebaseStart(self, onNotificationFunc, firebaseCredentialsFileName, brand='cupra'):
20
23
  """ Starts the firebase cloud messaging receiver """
21
- loop = asyncio.get_running_loop()
22
- credentials = await loop.run_in_executor(None, readFCMCredsFile, firebaseCredentialsFileName)
23
- #credentials = readFCMCredsFile(firebaseCredentialsFileName)
24
- if credentials == {}:
25
- credentials =''
24
+ try:
25
+ loop = asyncio.get_running_loop()
26
+ credentials = await loop.run_in_executor(None, readFCMCredsFile, firebaseCredentialsFileName)
27
+ #credentials = readFCMCredsFile(firebaseCredentialsFileName)
28
+ if credentials == {}:
29
+ credentials =''
26
30
 
27
- fcm_project_id=FCM_PROJECT_ID
28
- fcm_app_id=FCM_APP_ID[brand]
29
- fcm_api_key=FCM_API_KEY
30
- chars = string.ascii_letters + string.digits
31
- fcmMessageSenderId = ''.join(secrets.choice(chars) for i in range(16))
32
- fcmMessageSenderId= 'fxpWQ_'+fcmMessageSenderId
31
+ fcm_project_id=FCM_PROJECT_ID
32
+ fcm_app_id=FCM_APP_ID[brand]
33
+ fcm_api_key=FCM_API_KEY
34
+ chars = string.ascii_letters + string.digits
35
+ fcmMessageSenderId = ''.join(secrets.choice(chars) for i in range(16))
36
+ fcmMessageSenderId= 'fxpWQ_'+fcmMessageSenderId
33
37
 
38
+ fcm_config = FcmRegisterConfig(fcm_project_id, fcm_app_id, fcm_api_key, fcmMessageSenderId)
39
+ self._pushClient = FcmPushClient(onNotificationFunc, fcm_config, credentials, onFCMCredentialsUpdated)
40
+ fcm_token = await self._pushClient.checkin_or_register(firebaseCredentialsFileName)
41
+ _LOGGER.debug(f'Firebase.checkin_or_register() returned a token:{fcm_token}')
42
+ await self._pushClient.start()
43
+ await asyncio.sleep(5)
44
+ return self._pushClient.is_started()
45
+ except Exception as e:
46
+ _LOGGER.error('Error in firebaseStart. Error: {e}')
47
+ return False
34
48
 
35
- fcm_config = FcmRegisterConfig(fcm_project_id, fcm_app_id, fcm_api_key, fcmMessageSenderId)
36
- pc = FcmPushClient(onNotificationFunc, fcm_config, credentials, onFCMCredentialsUpdated)
37
- fcm_token = await pc.checkin_or_register(firebaseCredentialsFileName)
38
- _LOGGER.debug(f'Firebase.checkin_or_register() returned a token:{fcm_token}')
39
- await pc.start()
40
- await asyncio.sleep(5)
41
- return pc.is_started()
49
+ async def firebaseStop(self):
50
+ """ Stops the firebase cloud messaging receiver """
51
+ try:
52
+ await self._pushClient.stop()
53
+ #await asyncio.sleep(5)
54
+ self._pushClient = None
55
+ return True
56
+ except Exception as e:
57
+ _LOGGER.error('Error in firebaseStop. Error: {e}')
58
+ return False
42
59
 
43
60
  def readFCMCredsFile(credsFile):
44
61
  """ Reads the firebase cloud messaging credentials from file"""
@@ -52,8 +69,8 @@ def readFCMCredsFile(credsFile):
52
69
  else:
53
70
  _LOGGER.debug(f'{credsFile} not found.')
54
71
  return {}
55
- except:
56
- _LOGGER.warning('readFCMCredsFile() not successful.')
72
+ except Exception as e:
73
+ _LOGGER.warning('readFCMCredsFile() not successful. Error: {e}')
57
74
  return ''
58
75
 
59
76
  def writeFCMCredsFile(creds, firebaseCredentialsFileName):
pycupra/utilities.py CHANGED
@@ -1,116 +1,116 @@
1
- from datetime import date, datetime
2
- from base64 import b64encode
3
- from string import ascii_letters as letters, digits
4
- from sys import argv
5
- from os import environ as env
6
- from os.path import join, dirname, expanduser
7
- from itertools import product
8
- import json
9
- import logging
10
- import re
11
-
12
- _LOGGER = logging.getLogger(__name__)
13
-
14
-
15
- def read_config():
16
- """Read config from file."""
17
- for directory, filename in product(
18
- [
19
- dirname(argv[0]),
20
- expanduser("~"),
21
- env.get("XDG_CONFIG_HOME", join(expanduser("~"), ".config")),
22
- ],
23
- ["seat.conf", ".seat.conf"],
24
- ):
25
- try:
26
- config = join(directory, filename)
27
- _LOGGER.debug("checking for config file %s", config)
28
- with open(config) as config:
29
- return dict(
30
- x.split(": ")
31
- for x in config.read().strip().splitlines()
32
- if not x.startswith("#")
33
- )
34
- except (IOError, OSError):
35
- continue
36
- return {}
37
-
38
-
39
- def json_loads(s):
40
- return json.loads(s, object_hook=obj_parser)
41
-
42
-
43
- def obj_parser(obj):
44
- """Parse datetime."""
45
- for key, val in obj.items():
46
- try:
47
- obj[key] = datetime.strptime(val, "%Y-%m-%dT%H:%M:%S%z")
48
- except (TypeError, ValueError):
49
- pass
50
- return obj
51
-
52
-
53
- def find_path(src, path):
54
- """Simple navigation of a hierarchical dict structure using XPATH-like syntax.
55
-
56
- >>> find_path(dict(a=1), 'a')
57
- 1
58
-
59
- >>> find_path(dict(a=1), '')
60
- {'a': 1}
61
-
62
- >>> find_path(dict(a=None), 'a')
63
-
64
-
65
- >>> find_path(dict(a=1), 'b')
66
- Traceback (most recent call last):
67
- ...
68
- KeyError: 'b'
69
-
70
- >>> find_path(dict(a=dict(b=1)), 'a.b')
71
- 1
72
-
73
- >>> find_path(dict(a=dict(b=1)), 'a')
74
- {'b': 1}
75
-
76
- >>> find_path(dict(a=dict(b=1)), 'a.c')
77
- Traceback (most recent call last):
78
- ...
79
- KeyError: 'c'
80
-
81
- """
82
- if not path:
83
- return src
84
- if isinstance(path, str):
85
- path = path.split(".")
86
- return find_path(src[path[0]], path[1:])
87
-
88
-
89
- def is_valid_path(src, path):
90
- """
91
- >>> is_valid_path(dict(a=1), 'a')
92
- True
93
-
94
- >>> is_valid_path(dict(a=1), '')
95
- True
96
-
97
- >>> is_valid_path(dict(a=1), None)
98
- True
99
-
100
- >>> is_valid_path(dict(a=1), 'b')
101
- False
102
- """
103
- try:
104
- find_path(src, path)
105
- return True
106
- except KeyError:
107
- return False
108
-
109
-
110
- def camel2slug(s):
111
- """Convert camelCase to camel_case.
112
-
113
- >>> camel2slug('fooBar')
114
- 'foo_bar'
115
- """
116
- return re.sub("([A-Z])", "_\\1", s).lower().lstrip("_")
1
+ from datetime import date, datetime
2
+ from base64 import b64encode
3
+ from string import ascii_letters as letters, digits
4
+ from sys import argv
5
+ from os import environ as env
6
+ from os.path import join, dirname, expanduser
7
+ from itertools import product
8
+ import json
9
+ import logging
10
+ import re
11
+
12
+ _LOGGER = logging.getLogger(__name__)
13
+
14
+
15
+ def read_config():
16
+ """Read config from file."""
17
+ for directory, filename in product(
18
+ [
19
+ dirname(argv[0]),
20
+ expanduser("~"),
21
+ env.get("XDG_CONFIG_HOME", join(expanduser("~"), ".config")),
22
+ ],
23
+ ["seat.conf", ".seat.conf"],
24
+ ):
25
+ try:
26
+ config = join(directory, filename)
27
+ _LOGGER.debug("checking for config file %s", config)
28
+ with open(config) as config:
29
+ return dict(
30
+ x.split(": ")
31
+ for x in config.read().strip().splitlines()
32
+ if not x.startswith("#")
33
+ )
34
+ except (IOError, OSError):
35
+ continue
36
+ return {}
37
+
38
+
39
+ def json_loads(s):
40
+ return json.loads(s, object_hook=obj_parser)
41
+
42
+
43
+ def obj_parser(obj):
44
+ """Parse datetime."""
45
+ for key, val in obj.items():
46
+ try:
47
+ obj[key] = datetime.strptime(val, "%Y-%m-%dT%H:%M:%S%z")
48
+ except (TypeError, ValueError):
49
+ pass
50
+ return obj
51
+
52
+
53
+ def find_path(src, path):
54
+ """Simple navigation of a hierarchical dict structure using XPATH-like syntax.
55
+
56
+ >>> find_path(dict(a=1), 'a')
57
+ 1
58
+
59
+ >>> find_path(dict(a=1), '')
60
+ {'a': 1}
61
+
62
+ >>> find_path(dict(a=None), 'a')
63
+
64
+
65
+ >>> find_path(dict(a=1), 'b')
66
+ Traceback (most recent call last):
67
+ ...
68
+ KeyError: 'b'
69
+
70
+ >>> find_path(dict(a=dict(b=1)), 'a.b')
71
+ 1
72
+
73
+ >>> find_path(dict(a=dict(b=1)), 'a')
74
+ {'b': 1}
75
+
76
+ >>> find_path(dict(a=dict(b=1)), 'a.c')
77
+ Traceback (most recent call last):
78
+ ...
79
+ KeyError: 'c'
80
+
81
+ """
82
+ if not path:
83
+ return src
84
+ if isinstance(path, str):
85
+ path = path.split(".")
86
+ return find_path(src[path[0]], path[1:])
87
+
88
+
89
+ def is_valid_path(src, path):
90
+ """
91
+ >>> is_valid_path(dict(a=1), 'a')
92
+ True
93
+
94
+ >>> is_valid_path(dict(a=1), '')
95
+ True
96
+
97
+ >>> is_valid_path(dict(a=1), None)
98
+ True
99
+
100
+ >>> is_valid_path(dict(a=1), 'b')
101
+ False
102
+ """
103
+ try:
104
+ find_path(src, path)
105
+ return True
106
+ except KeyError:
107
+ return False
108
+
109
+
110
+ def camel2slug(s):
111
+ """Convert camelCase to camel_case.
112
+
113
+ >>> camel2slug('fooBar')
114
+ 'foo_bar'
115
+ """
116
+ return re.sub("([A-Z])", "_\\1", s).lower().lstrip("_")
pycupra/vehicle.py CHANGED
@@ -34,7 +34,7 @@ _LOGGER = logging.getLogger(__name__)
34
34
  DATEZERO = datetime(1970,1,1)
35
35
  class Vehicle:
36
36
  def __init__(self, conn, data):
37
- _LOGGER.debug(f'Creating Vehicle class object with data {data}')
37
+ _LOGGER.debug(conn.anonymise(f'Creating Vehicle class object with data {data}'))
38
38
  self._connection = conn
39
39
  self._url = data.get('vin', '')
40
40
  self._connectivities = data.get('connectivities', '')
@@ -50,6 +50,7 @@ class Vehicle:
50
50
  self._firebaseCredentialsFileName = None
51
51
  self._firebaseLastMessageId = ''
52
52
  self.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
53
+ self.firebase = None
53
54
  self.updateCallback = None
54
55
 
55
56
  self._requests = {
@@ -76,6 +77,7 @@ class Vehicle:
76
77
  'vehicleHealthWarnings': {'active': False, 'reason': 'not supported'},
77
78
  'state': {'active': False, 'reason': 'not supported'},
78
79
  'charging': {'active': False, 'reason': 'not supported', 'supportsTargetStateOfCharge': False},
80
+ 'chargingProfiles': {'active': False, 'reason': 'not supported', "supportsTimerClimatisation": False,"supportsVehiclePositionedInProfileID": False,"supportsSingleTimer": False},
79
81
  'honkAndFlash': {'active': False, 'reason': 'not supported'},
80
82
  'parkingPosition': {'active': False, 'reason': 'not supported'},
81
83
  'departureTimers': {'active': False, 'reason': 'not supported', 'supportsSingleTimer': False},
@@ -121,6 +123,10 @@ class Vehicle:
121
123
  data['supportsTargetStateOfCharge']=True
122
124
  if capa['parameters'].get('supportsSingleTimer',False)==True or capa['parameters'].get('supportsSingleTimer',False)=='true':
123
125
  data['supportsSingleTimer']=True
126
+ if capa['parameters'].get('supportsVehiclePositionedInProfileID',False)==True or capa['parameters'].get('supportsVehiclePositionedInProfileID',False)=='true':
127
+ data['supportsVehiclePositionedInProfileID']=True
128
+ if capa['parameters'].get('supportsTimerClimatisation',False)==True or capa['parameters'].get('supportsTimerClimatisation',False)=='true':
129
+ data['supportsTimerClimatisation']=True
124
130
  self._relevantCapabilties[id].update(data)
125
131
 
126
132
 
@@ -179,7 +185,7 @@ class Vehicle:
179
185
  if hasattr(self, '_last_full_update'):
180
186
  _LOGGER.debug(f'last_full_update= {self._last_full_update}, fullUpdateExpired= {fullUpdateExpired}.')
181
187
  if updateType!=1 and (hasattr(self, '_last_full_update') and self._last_full_update>fullUpdateExpired):
182
- _LOGGER.debug(f'Just performed small update for vehicle with VIN {self.vin}.')
188
+ _LOGGER.debug(f'Just performed small update for vehicle with VIN {self._connection.anonymise(self.vin)}.')
183
189
  return True
184
190
 
185
191
  # Data to be updated less often
@@ -201,13 +207,13 @@ class Vehicle:
201
207
  return_exceptions=True
202
208
  )
203
209
  self._last_full_update = datetime.now(tz=None)
204
- _LOGGER.debug(f'Performed full update for vehicle with VIN {self.vin}.')
210
+ _LOGGER.debug(f'Performed full update for vehicle with VIN {self._connection.anonymise(self.vin)}.')
205
211
  _LOGGER.debug(f'So far about {self._connection._sessionRequestCounter} API calls since {self._connection._sessionRequestTimestamp}.')
206
212
  except:
207
213
  raise SeatException("Update failed")
208
214
  return True
209
215
  else:
210
- _LOGGER.info(f'Vehicle with VIN {self.vin} is deactivated.')
216
+ _LOGGER.info(f'Vehicle with VIN {self._connection.anonymise(self.vin)} is deactivated.')
211
217
  return False
212
218
  return True
213
219
 
@@ -245,7 +251,7 @@ class Vehicle:
245
251
  async def get_climater(self):
246
252
  """Fetch climater data if function is enabled."""
247
253
  if self._relevantCapabilties.get('climatisation', {}).get('active', False):
248
- data = await self._connection.getClimater(self.vin, self._apibase)
254
+ data = await self._connection.getClimater(self.vin, self._apibase, deepcopy(self.attrs.get('climater',{})))
249
255
  if data:
250
256
  self._states.update(data)
251
257
  self._last_get_climater = datetime.now(tz=None)
@@ -285,6 +291,14 @@ class Vehicle:
285
291
  if self._relevantCapabilties.get('vehicleHealthWarnings', {}).get('active', False):
286
292
  data = await self._connection.getVehicleHealthWarnings(self.vin, self._apibase)
287
293
  if data:
294
+ #warningsList = data.get('warninglights',{}).get('statuses',[])
295
+ #for i in range(len(warningsList)):
296
+ # _LOGGER.debug(f'Element {i} in warninglights: {warningsList[i]}')
297
+ # if isinstance(warningsList[i], dict):
298
+ # if warningsList[i].get('icon',''):
299
+ # #Value of icon is very long and can lead to problems
300
+ # _LOGGER.debug(f'Substituting value of icon by \'DELETED\'')
301
+ # data['warninglights']['statuses'][i]['icon']='DELETED'
288
302
  self._states.update(data)
289
303
  else:
290
304
  _LOGGER.debug('Could not fetch vehicle health warnings')
@@ -311,7 +325,7 @@ class Vehicle:
311
325
  async def get_charger(self):
312
326
  """Fetch charger data if function is enabled."""
313
327
  if self._relevantCapabilties.get('charging', {}).get('active', False):
314
- data = await self._connection.getCharger(self.vin, self._apibase)
328
+ data = await self._connection.getCharger(self.vin, self._apibase, deepcopy(self.attrs.get('charging',{})))
315
329
  if data:
316
330
  self._states.update(data)
317
331
  self._last_get_charger = datetime.now(tz=None)
@@ -396,6 +410,33 @@ class Vehicle:
396
410
  _LOGGER.error('No charger support.')
397
411
  raise SeatInvalidRequestException('No charger support.')
398
412
 
413
+ async def set_charger_target_soc(self, value):
414
+ """Set target state of charge"""
415
+ if self.is_charging_supported:
416
+ if isinstance(value, int):
417
+ if 1 <= int(value) <= 100:
418
+ # VW-Group API charger current request
419
+ if self._relevantCapabilties.get('charging', {}).get('active', False) and self._relevantCapabilties.get('charging', {}).get('supportsTargetStateOfCharge', False):
420
+ data= deepcopy(self.attrs.get('charging',{}).get('info',{}).get('settings',{}))
421
+ if data=={}:
422
+ _LOGGER.error(f'Can not set target soc, because currently no charging settings are present.')
423
+ raise SeatInvalidRequestException(f'Set target soc not possible. Charging settings not present.')
424
+ data['targetSoc'] = int(value)
425
+ else:
426
+ _LOGGER.warning(f'Can not set target soc, because vehicle does not support this feature.')
427
+ return False
428
+ else:
429
+ _LOGGER.error(f'Set target soc to {value} is not supported.')
430
+ raise SeatInvalidRequestException(f'Set target soc to {value} is not supported.')
431
+ # Mimick app and set charger max ampere to Maximum/Reduced
432
+ else:
433
+ _LOGGER.error(f'Data type passed is invalid.')
434
+ raise SeatInvalidRequestException(f'Invalid data type.')
435
+ return await self.set_charger('settings', data)
436
+ else:
437
+ _LOGGER.error('No charger support.')
438
+ raise SeatInvalidRequestException('No charger support.')
439
+
399
440
  async def set_charger(self, action, data=None):
400
441
  """Charging actions."""
401
442
  if not self._relevantCapabilties.get('charging', {}).get('active', False):
@@ -450,9 +491,11 @@ class Vehicle:
450
491
  if not self.charging:
451
492
  actionSuccessful = True
452
493
  elif mode == 'settings':
494
+ if data.get('targetSoc',0) == self.target_soc: # In case targetSoc is changed
495
+ actionSuccessful = True
453
496
  if data.get('maxChargeCurrentAc','') == self.charge_max_ampere: # In case 'maximum', 'reduced'
454
497
  actionSuccessful = True
455
- if data.get('maxChargeCurrentAcInAmperes',0) == self.charge_max_ampere: # In case of a numerical value
498
+ if data.get('maxChargeCurrentAcInAmperes',0) == self.charge_max_ampere: # In case of a numerical value for charge current
456
499
  actionSuccessful = True
457
500
  else:
458
501
  _LOGGER.error(f'Missing code in vehicle._set_charger() for mode {mode}')
@@ -1360,6 +1403,17 @@ class Vehicle:
1360
1403
  # if car.get('deactivated', False):
1361
1404
  # return True
1362
1405
 
1406
+ @property
1407
+ def brand(self):
1408
+ """Return brand"""
1409
+ return self._specification.get('factoryModel', False).get('vehicleBrand', 'Unknown')
1410
+
1411
+ @property
1412
+ def is_brand_supported(self):
1413
+ """Return true if brand is supported."""
1414
+ if self._specification.get('factoryModel', False).get('vehicleBrand', False):
1415
+ return True
1416
+
1363
1417
  @property
1364
1418
  def model(self):
1365
1419
  """Return model"""
@@ -2183,7 +2237,12 @@ class Vehicle:
2183
2237
  def warnings(self):
2184
2238
  """Return warnings."""
2185
2239
  if self.attrs.get('warninglights', {}).get('statuses',[]):
2186
- return self.attrs.get('warninglights', {}).get('statuses',[])
2240
+ warningTextList = []
2241
+ for elem in self.attrs['warninglights']['statuses']:
2242
+ if isinstance(elem, dict):
2243
+ if elem.get('text',''):
2244
+ warningTextList.append(elem.get('text',''))
2245
+ return warningTextList
2187
2246
  return 'No warnings'
2188
2247
 
2189
2248
  @property
@@ -3086,6 +3145,27 @@ class Vehicle:
3086
3145
  )
3087
3146
 
3088
3147
 
3148
+ async def stopFirebase(self):
3149
+ # Check if firebase is activated
3150
+ if self.firebaseStatus!= FIREBASE_STATUS_ACTIVATED:
3151
+ _LOGGER.info(f'No need to stop firebase. Firebase status={self.firebaseStatus}')
3152
+ return self.firebaseStatus
3153
+
3154
+ if self.firebase == None:
3155
+ _LOGGER.error(f'Internal error: Firebase status={self.firebaseStatus} but firebase variable not set. Setting firebase status back to not initialised.')
3156
+ self.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
3157
+ return self.firebaseStatus
3158
+
3159
+ success = await self.firebase.firebaseStop()
3160
+ if not success:
3161
+ _LOGGER.warning('Stopping of firebase messaging failed.')
3162
+ return self.firebaseStatus
3163
+
3164
+ #await asyncio.sleep(5) # Wait to ignore the first notifications
3165
+ self.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
3166
+ _LOGGER.info('Stopping of firebase messaging was successful.')
3167
+ return self.firebaseStatus
3168
+
3089
3169
  async def initialiseFirebase(self, firebaseCredentialsFileName=None, updateCallback=None):
3090
3170
  # Check if firebase shall be used
3091
3171
  if firebaseCredentialsFileName == None:
@@ -3107,12 +3187,13 @@ class Vehicle:
3107
3187
  subscribedBrand = credentials.get('subscription',{}).get('brand','')
3108
3188
  if subscribedVin != '' and subscribedUserId != '':
3109
3189
  if subscribedVin != self.vin or subscribedUserId != self._connection._user_id or subscribedBrand != self._connection._session_auth_brand:
3110
- _LOGGER.debug(f'Change of vin, userId or brand. Deleting subscription for vin={subscribedVin} and userId={subscribedUserId}.')
3190
+ _LOGGER.debug(self._connection.anonymise(f'Change of vin, userId or brand. Deleting subscription for vin={subscribedVin} and userId={subscribedUserId}.'))
3111
3191
  result = await self._connection.deleteSubscription(credentials)
3112
3192
 
3113
3193
  # Start firebase
3114
- fb = Firebase()
3115
- success = await fb.firebaseStart(self.onNotification, firebaseCredentialsFileName, brand=self._connection._session_auth_brand)
3194
+ if self.firebase == None:
3195
+ self.firebase = Firebase()
3196
+ success = await self.firebase.firebaseStart(self.onNotification, firebaseCredentialsFileName, brand=self._connection._session_auth_brand)
3116
3197
  if not success:
3117
3198
  self.firebaseStatus = FIREBASE_STATUS_ACTIVATION_FAILED
3118
3199
  _LOGGER.warning('Activation of firebase messaging failed.')
@@ -3133,7 +3214,7 @@ class Vehicle:
3133
3214
  loop = asyncio.get_running_loop()
3134
3215
  await loop.run_in_executor(None, writeFCMCredsFile, credentials, firebaseCredentialsFileName)
3135
3216
 
3136
- await asyncio.sleep(5) # Wait to let the first notifications
3217
+ await asyncio.sleep(5) # Wait to ignore the first notifications
3137
3218
  self.firebaseStatus = FIREBASE_STATUS_ACTIVATED
3138
3219
  _LOGGER.info('Activation of firebase messaging was successful.')
3139
3220
  return self.firebaseStatus
@@ -3150,7 +3231,7 @@ class Vehicle:
3150
3231
  self.storeFirebaseNotifications(obj, notification, data_message)
3151
3232
 
3152
3233
  if self.firebaseStatus != FIREBASE_STATUS_ACTIVATED:
3153
- _LOGGER.info(f'While firebase is not fully activated, received notifications are just acknoledged.')
3234
+ _LOGGER.info(f'While firebase is not fully activated, received notifications are just acknowledged.')
3154
3235
  # As long as the firebase status is not set to activated, ignore the notifications
3155
3236
  return False
3156
3237
 
@@ -3200,7 +3281,7 @@ class Vehicle:
3200
3281
  await self.get_departure_profiles()
3201
3282
  if self.updateCallback:
3202
3283
  await self.updateCallback(2)
3203
- elif type in ('charging-status-changed', 'charging-started', 'charging-stopped'):
3284
+ elif type in ('charging-status-changed', 'charging-started', 'charging-stopped', 'charging-settings-updated'):
3204
3285
  if self._requests.get('batterycharge', {}).get('id', None):
3205
3286
  openRequest= self._requests.get('batterycharge', {}).get('id', None)
3206
3287
  if openRequest == requestId:
@@ -3213,7 +3294,7 @@ class Vehicle:
3213
3294
  await self.updateCallback(2)
3214
3295
  else:
3215
3296
  _LOGGER.debug(f'It is now {datetime.now(tz=None)}. Last get_charger was at {self._last_get_charger}. So no need to update.')
3216
- elif type in ('climatisation-status-changed','climatisation-started', 'climatisation-stopped'):
3297
+ elif type in ('climatisation-status-changed','climatisation-started', 'climatisation-stopped', 'climatisation-settings-updated'):
3217
3298
  if self._requests.get('climatisation', {}).get('id', None):
3218
3299
  openRequest= self._requests.get('climatisation', {}).get('id', None)
3219
3300
  if openRequest == requestId:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycupra
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: A library to read and send vehicle data via Cupra/Seat portal using the same API calls as the MyCupra/MySeat mobile app.
5
5
  Home-page: https://github.com/WulfgarW/pycupra
6
6
  Author: WulfgarW
@@ -1,12 +1,12 @@
1
1
  pycupra/__init__.py,sha256=p0880jPkLqOErX3u3qaLboBLOsEHFpe44axApdaGeqI,231
2
- pycupra/__version__.py,sha256=eKzk7G69_LtPVYjNt3lX5LnPJXkUoj0G0EKvXxByrlA,207
3
- pycupra/connection.py,sha256=r02CHAhRrZwu90AIsfTnzAhRn9dZjK8WuZvhUa6_DcA,85314
2
+ pycupra/__version__.py,sha256=orABFX8h4AFdsffPt4uVXqXeC0Wz3ZJOeNAzyeNw7O8,207
3
+ pycupra/connection.py,sha256=cZIqsjEwA1rTkhVyjowrTdbWnviOXFSso-WR8FnSrmg,90610
4
4
  pycupra/const.py,sha256=cJJ9xrof6HZ7ZE7nXnB6tU4qMbSadlN8mgs43Igy7Mo,10591
5
- pycupra/dashboard.py,sha256=hFHhCDrCNufQR1I85AlR4kPgSlFSinCegZ0w8F4FvUk,43703
5
+ pycupra/dashboard.py,sha256=RlJPdTvJV7Urog5gCz_4pYWNd5_ApQIVJUCwJIi_7L8,43822
6
6
  pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
7
- pycupra/firebase.py,sha256=V3Ico6FZzEn0-5-CnqaDP9Mg9LpVU-_qLyZQwiRBbD0,2725
8
- pycupra/utilities.py,sha256=cH4MiIzT2WlHgmnl_E7rR0R5LvCXfDNvirJolct50V8,2563
9
- pycupra/vehicle.py,sha256=armeMQHxOZyyQJ9Iu7G26pq_BNc8oahPFxOe7daEip8,151994
7
+ pycupra/firebase.py,sha256=tuN_W3OX3h3-yfdprWzmCn6z_T-BMx-OpL7Z6hOA8Lc,3451
8
+ pycupra/utilities.py,sha256=6sDxWP13-XtxmqhuBJBGdVbkj48BQ9AxFMrBPxH0J7g,2679
9
+ pycupra/vehicle.py,sha256=stxeyn2vd2j2yQ3dWEmT9XX1aZNZ7FdYvxbIraF6M0o,157175
10
10
  pycupra/firebase_messaging/__init__.py,sha256=oerLHWvEf4qRqu3GxSX6SLY_OYI430ydAiAhKtzyMEM,666
11
11
  pycupra/firebase_messaging/android_checkin_pb2.py,sha256=-U1oGroFt3KRuGDieae3iTcux6mAfx1TFkE1Q35ul2E,2849
12
12
  pycupra/firebase_messaging/android_checkin_pb2.pyi,sha256=7KL-zQIz2Zz7uftcLkv57Podzu-yk6trn50FN4X4A8E,9379
@@ -18,8 +18,8 @@ pycupra/firebase_messaging/fcmregister.py,sha256=yZngC-0ZfTygtjfdzg03OW_3xk2n_uS
18
18
  pycupra/firebase_messaging/mcs_pb2.py,sha256=nwXY7IDgLYPxgpSGs6wyTSyYDdomQsyGqH8R8EgODLg,7733
19
19
  pycupra/firebase_messaging/mcs_pb2.pyi,sha256=HfIhInC3wRg8_caKwUm-V3knE2jTdEQvBy6uXgQ5rHY,33959
20
20
  pycupra/firebase_messaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- pycupra-0.1.4.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
22
- pycupra-0.1.4.dist-info/METADATA,sha256=zuQir0nJmXg_oS0xpQKEhyjL1Ub7rghOayNvNPSZvpU,3757
23
- pycupra-0.1.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
24
- pycupra-0.1.4.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
25
- pycupra-0.1.4.dist-info/RECORD,,
21
+ pycupra-0.1.6.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
22
+ pycupra-0.1.6.dist-info/METADATA,sha256=u9ZdIDY607S5-5APn3VwI1nJgvWHPngzptNHedmY_k4,3757
23
+ pycupra-0.1.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
24
+ pycupra-0.1.6.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
25
+ pycupra-0.1.6.dist-info/RECORD,,