pycupra 0.1.12__tar.gz → 0.1.14__tar.gz

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.
Files changed (42) hide show
  1. {pycupra-0.1.12 → pycupra-0.1.14}/.gitignore +10 -10
  2. pycupra-0.1.14/PKG-INFO +63 -0
  3. {pycupra-0.1.12 → pycupra-0.1.14}/example/PyCupra.py +12 -4
  4. pycupra-0.1.14/example/PyCupra_ExportDrivingData.py +113 -0
  5. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/connection.py +78 -68
  6. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/dashboard.py +36 -36
  7. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase.py +11 -8
  8. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/android_checkin_pb2.pyi +257 -257
  9. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/fcmpushclient.py +8 -7
  10. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/fcmregister.py +3 -3
  11. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/utilities.py +2 -26
  12. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/vehicle.py +299 -226
  13. pycupra-0.1.14/pycupra.egg-info/PKG-INFO +63 -0
  14. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra.egg-info/SOURCES.txt +1 -2
  15. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra.egg-info/requires.txt +4 -0
  16. pycupra-0.1.14/pycupra.egg-info/top_level.txt +3 -0
  17. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra_credentials.json.demo +1 -0
  18. pycupra-0.1.14/pyproject.toml +27 -0
  19. pycupra-0.1.12/PKG-INFO +0 -13
  20. pycupra-0.1.12/pycupra/__version__.py +0 -6
  21. pycupra-0.1.12/pycupra.egg-info/PKG-INFO +0 -13
  22. pycupra-0.1.12/pycupra.egg-info/top_level.txt +0 -1
  23. pycupra-0.1.12/pyproject.toml +0 -16
  24. pycupra-0.1.12/requirements.txt +0 -6
  25. {pycupra-0.1.12 → pycupra-0.1.14}/LICENSE +0 -0
  26. {pycupra-0.1.12 → pycupra-0.1.14}/README.md +0 -0
  27. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/__init__.py +0 -0
  28. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/const.py +0 -0
  29. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/exceptions.py +0 -0
  30. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/__init__.py +0 -0
  31. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/android_checkin.proto +0 -0
  32. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/android_checkin_pb2.py +0 -0
  33. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/checkin.proto +0 -0
  34. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/checkin_pb2.py +0 -0
  35. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/checkin_pb2.pyi +0 -0
  36. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/const.py +0 -0
  37. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/mcs.proto +0 -0
  38. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/mcs_pb2.py +0 -0
  39. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/mcs_pb2.pyi +0 -0
  40. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra/firebase_messaging/py.typed +0 -0
  41. {pycupra-0.1.12 → pycupra-0.1.14}/pycupra.egg-info/dependency_links.txt +0 -0
  42. {pycupra-0.1.12 → pycupra-0.1.14}/setup.cfg +0 -0
@@ -1,10 +1,10 @@
1
-
2
- .eggs/
3
- *.egg-info/
4
- build/
5
- dist/
6
- __pycache__/
7
- *.json
8
- *.txt
9
- *.log
10
- www/
1
+
2
+ .eggs/
3
+ *.egg-info/
4
+ build/
5
+ dist/
6
+ __pycache__/
7
+ *.json
8
+ *.txt
9
+ *.log
10
+ *.png
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: pycupra
3
+ Version: 0.1.14
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
+ License-Expression: Apache-2.0
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: aiohttp
10
+ Requires-Dist: beautifulsoup4
11
+ Requires-Dist: cryptography
12
+ Requires-Dist: lxml
13
+ Requires-Dist: PyJWT
14
+ Requires-Dist: xmltodict
15
+ Requires-Dist: pandas
16
+ Requires-Dist: pillow
17
+ Requires-Dist: protobuf
18
+ Requires-Dist: http-ece
19
+ Requires-Dist: requests-oauthlib
20
+ Dynamic: license-file
21
+
22
+ # PyCupra
23
+
24
+ A library to read and send vehicle data via Cupra/Seat portal using the same API calls as the MyCupra/MySeat mobile app.
25
+
26
+ Fork of https://github.com/Farfar/seatconnect which in turn is a fork of:
27
+ Fork of https://github.com/lendy007/skodaconnect which in turn is a fork of:
28
+ https://github.com/robinostlund/volkswagencarnet
29
+
30
+ ## Information
31
+
32
+ Retrieve statistics about your Cupra/Seat from the Cupra/Seat Connect online service
33
+
34
+ No licence, public domain, no guarantees, feel free to use for anything. Please contribute improvements/bugfixes etc.
35
+
36
+ ## Breaking changes
37
+
38
+ - The method vehicle.update(updateType) supports 3 different update types:
39
+ - updateType=0: Small update (=only get_basiccardata() and get_statusreport are called). If the last full update is more than 1100 seconds ago, then a full update is performed.
40
+ - updateType=1: Full update (nearly all get-methods are called. The model images and the capabilitites are refreshed only every 2 hours.)
41
+ - updateType=2: Like updateType=0, but ignoring the nightly update reduction
42
+
43
+ - Nightly update reduction: If nightly reduction is activated and the current time is within the time frame between 22:00 and 05:00, then vehicle.update(0) performs a full update, if the last full update is more than 1700 seconds ago. If that's not the case, vehicle.update(0) does nothing.
44
+
45
+ - PyCupra can ask the Seat/Cupra portal to send push notifications to PyCupra if the charging status or the climatisation status has changed or when the API has finished a request like lock or unlock vehicle, start or stop charging or change departure timers or ....
46
+
47
+ ## Thanks to
48
+
49
+ - [RobinostLund](https://github.com/robinostlund/volkswagencarnet) for initial project for Volkswagen Carnet I was able to fork
50
+ - [Farfar](https://github.com/Farfar) for modifications related to electric engines
51
+ - [tanelvakker](https://github.com/tanelvakker) for modifications related to correct SPIN handling for various actions and using correct URLs also for MY2021
52
+ - [sdb9696](https://github.com/sdb9696) for the firebase-messaging package that is used in PyCupra with only minor modifications
53
+
54
+ ### Example
55
+
56
+ For an extensive example, please use the code found in example/PyCupra.py.
57
+ When logged in the library will automatically create a vehicle object for every car registered to the account. Initially no data is fetched at all. Use the doLogin method and it will signin with the credentials used for the class constructor. After a successful login, the tokens are stored in a json file. Later doLogin calls can use the token file instead of the credentials.
58
+ Method get_vehicles will fetch vehicle basic information and create Vehicle class objects for all associated vehicles in account.
59
+ To update all available data use the update_all method of the Connect class. This will call the update function for all registered vehicles, which in turn will fetch data from all available API endpoints.
60
+
61
+ The file *pycupra_credentials.json.demo* explains the data structure of the credentials file.
62
+
63
+
@@ -10,9 +10,11 @@ import pandas as pd
10
10
  from aiohttp import ClientSession
11
11
  from datetime import datetime
12
12
 
13
- currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
14
- parentdir = os.path.dirname(currentdir)
15
- sys.path.insert(0, parentdir)
13
+ currentframe = inspect.currentframe()
14
+ if currentframe != None:
15
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(currentframe)))
16
+ parentdir = os.path.dirname(currentdir)
17
+ sys.path.insert(0, parentdir)
16
18
 
17
19
  try:
18
20
  from pycupra import Connection
@@ -383,6 +385,12 @@ async def main():
383
385
  if credentials==None or credentials.get('username','')=='' or (credentials.get('password','')==''):
384
386
  _LOGGER.warning('Can not use the credentials read from the credentials file.')
385
387
  raise
388
+ if credentials.get('brand','')!='':
389
+ BRAND = credentials.get('brand','')
390
+ print('Read brand from the credentials file.')
391
+ else:
392
+ print('No brand found in the credentials file. Using the default value.')
393
+ print(f'Now working with brand={BRAND}')
386
394
  async with ClientSession(headers={'Connection': 'keep-alive'}) as session:
387
395
  print('')
388
396
  print('######################################################')
@@ -594,7 +602,7 @@ async def main():
594
602
  i=i+1
595
603
  _LOGGER.debug(f'Round {i}')
596
604
 
597
- exit
605
+ sys.exit(1)
598
606
 
599
607
  if __name__ == "__main__":
600
608
  loop = asyncio.new_event_loop()
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python3
2
+ """ Sample program to export the trip statistics as csv file"""
3
+ import asyncio
4
+ import logging
5
+ import inspect
6
+ import sys
7
+ import os
8
+ import json
9
+ import pandas as pd
10
+ from aiohttp import ClientSession
11
+ from datetime import datetime
12
+
13
+ currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
14
+ parentdir = os.path.dirname(currentdir)
15
+ sys.path.insert(0, parentdir)
16
+
17
+ try:
18
+ from pycupra import Connection
19
+ except ModuleNotFoundError as e:
20
+ print(f"Unable to import library: {e}")
21
+ sys.exit(1)
22
+
23
+ logging.basicConfig(level=logging.WARN)
24
+ _LOGGER = logging.getLogger(__name__)
25
+ BRAND = 'cupra' # or 'seat' (Default value if no brand is provided via credentials file)
26
+
27
+ PRINTRESPONSE = True
28
+ INTERVAL = 5
29
+ TOKEN_FILE_NAME_AND_PATH='./pycupra_token.json'
30
+ CREDENTIALS_FILE_NAME_AND_PATH='./pycupra_credentials.json'
31
+
32
+ def readCredentialsFile():
33
+ try:
34
+ with open(CREDENTIALS_FILE_NAME_AND_PATH, "r") as f:
35
+ credentialsString=f.read()
36
+ credentials=json.loads(credentialsString)
37
+ return credentials
38
+ except:
39
+ _LOGGER.info('readCredentialsFile not successful. Perhaps no credentials file present.')
40
+ return None
41
+
42
+ def exportToCSV(vehicle, csvFileName, dataType='short'):
43
+ df= pd.DataFrame(vehicle._states['tripstatistics'][dataType])
44
+ _LOGGER.debug('Exporting trip data to csv')
45
+ df.to_csv(csvFileName)
46
+ return True
47
+
48
+ async def main():
49
+ """Main method."""
50
+ print('')
51
+ print('######################################################')
52
+ print('# Reading credentials file #')
53
+ print('######################################################')
54
+ credentials= readCredentialsFile()
55
+ if credentials==None or credentials.get('username','')=='' or (credentials.get('password','')==''):
56
+ _LOGGER.warning('Can not use the credentials read from the credentials file.')
57
+ raise
58
+ if credentials.get('brand','')!='':
59
+ BRAND = credentials.get('brand','')
60
+ print('Read brand from the credentials file.')
61
+ else:
62
+ print('No brand found in the credentials file. Using the default value.')
63
+ print(f'Now working with brand={BRAND}')
64
+ async with ClientSession(headers={'Connection': 'keep-alive'}) as session:
65
+ print('')
66
+ print('######################################################')
67
+ print('# Logging on to ola.prod.code.seat.cloud.vwgroup.com #')
68
+ print('######################################################')
69
+ print(f"Initiating new session to Cupra/Seat Cloud with {credentials.get('username')} as username")
70
+ connection = Connection(session, BRAND, credentials.get('username'), credentials.get('password'), PRINTRESPONSE, nightlyUpdateReduction=False, anonymise=True, tripStatisticsStartDate='1970-01-01')
71
+ print("Attempting to login to the Seat Cloud service")
72
+ if await connection.doLogin(tokenFile=TOKEN_FILE_NAME_AND_PATH, apiKey=credentials.get('apiKey',None)):
73
+ print('Login or token refresh success!')
74
+ print(datetime.now())
75
+ print('Fetching user information for account.')
76
+ await connection.get_userData()
77
+ print(f"\tName: {connection._userData.get('name','')}")
78
+ print(f"\tNickname: {connection._userData.get('nickname','')}")
79
+ print(f"\tEmail: {connection._userData.get('email','')}")
80
+ print(f"\tPicture: {connection._userData.get('picture','')}")
81
+ print("")
82
+ print('Fetching vehicles associated with account.')
83
+ await connection.get_vehicles()
84
+
85
+ print('')
86
+ print('########################################')
87
+ print('# Vehicles discovered #')
88
+ print('########################################')
89
+ for vehicle in connection.vehicles:
90
+ print(f"\tVIN: {vehicle.vin}")
91
+ print(f"\tModel: {vehicle.model}")
92
+ print(f"\tManufactured: {vehicle.model_year}")
93
+ print(f"\tConnect service deactivated: {vehicle.deactivated}")
94
+ print("")
95
+ if vehicle.is_nickname_supported: print(f"\tNickname: {vehicle.nickname}")
96
+ else:
97
+ return False
98
+
99
+ for vehicle in connection.vehicles:
100
+ txt = vehicle.vin
101
+ print('########################################')
102
+ print('# Export driving data to csv #')
103
+ print(txt.center(40, '#'))
104
+ exportToCSV(vehicle, credentials.get('csvFileName','./drivingData.csv'), 'short') # possible value: short/cyclic
105
+ print('')
106
+ print('Export of driving data to csv complete')
107
+ sys.exit(1)
108
+
109
+ if __name__ == "__main__":
110
+ loop = asyncio.new_event_loop()
111
+ asyncio.set_event_loop(loop)
112
+ loop.run_until_complete(main())
113
+