pycupra 0.0.15__tar.gz → 0.1.1__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 (38) hide show
  1. {pycupra-0.0.15/pycupra.egg-info → pycupra-0.1.1}/PKG-INFO +12 -2
  2. {pycupra-0.0.15 → pycupra-0.1.1}/README.md +11 -1
  3. {pycupra-0.0.15 → pycupra-0.1.1}/example/PyCupra.py +23 -8
  4. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/__init__.py +1 -0
  5. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/__version__.py +1 -1
  6. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/connection.py +66 -9
  7. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/const.py +11 -0
  8. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/dashboard.py +7 -0
  9. pycupra-0.1.1/pycupra/firebase.py +73 -0
  10. pycupra-0.1.1/pycupra/firebase_messaging/__init__.py +20 -0
  11. pycupra-0.1.1/pycupra/firebase_messaging/const.py +32 -0
  12. pycupra-0.1.1/pycupra/firebase_messaging/fcmpushclient.py +796 -0
  13. pycupra-0.1.1/pycupra/firebase_messaging/fcmregister.py +519 -0
  14. pycupra-0.1.1/pycupra/firebase_messaging/proto/android_checkin.proto +96 -0
  15. pycupra-0.1.1/pycupra/firebase_messaging/proto/android_checkin_pb2.py +36 -0
  16. pycupra-0.1.1/pycupra/firebase_messaging/proto/android_checkin_pb2.pyi +257 -0
  17. pycupra-0.1.1/pycupra/firebase_messaging/proto/checkin.proto +155 -0
  18. pycupra-0.1.1/pycupra/firebase_messaging/proto/checkin_pb2.py +31 -0
  19. pycupra-0.1.1/pycupra/firebase_messaging/proto/checkin_pb2.pyi +424 -0
  20. pycupra-0.1.1/pycupra/firebase_messaging/proto/mcs.proto +328 -0
  21. pycupra-0.1.1/pycupra/firebase_messaging/proto/mcs_pb2.py +65 -0
  22. pycupra-0.1.1/pycupra/firebase_messaging/proto/mcs_pb2.pyi +1118 -0
  23. pycupra-0.1.1/pycupra/firebase_messaging/py.typed +0 -0
  24. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/vehicle.py +257 -13
  25. {pycupra-0.0.15 → pycupra-0.1.1/pycupra.egg-info}/PKG-INFO +12 -2
  26. pycupra-0.1.1/pycupra.egg-info/SOURCES.txt +36 -0
  27. pycupra-0.0.15/pycupra.egg-info/SOURCES.txt +0 -21
  28. {pycupra-0.0.15 → pycupra-0.1.1}/.gitignore +0 -0
  29. {pycupra-0.0.15 → pycupra-0.1.1}/LICENSE +0 -0
  30. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/exceptions.py +0 -0
  31. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra/utilities.py +0 -0
  32. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra.egg-info/dependency_links.txt +0 -0
  33. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra.egg-info/requires.txt +0 -0
  34. {pycupra-0.0.15 → pycupra-0.1.1}/pycupra.egg-info/top_level.txt +0 -0
  35. /pycupra-0.0.15/cupra_credentials.json.demo → /pycupra-0.1.1/pycupra_credentials.json.demo +0 -0
  36. {pycupra-0.0.15 → pycupra-0.1.1}/requirements.txt +0 -0
  37. {pycupra-0.0.15 → pycupra-0.1.1}/setup.cfg +0 -0
  38. {pycupra-0.0.15 → pycupra-0.1.1}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pycupra
3
- Version: 0.0.15
3
+ Version: 0.1.1
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
@@ -39,11 +39,21 @@ No licence, public domain, no guarantees, feel free to use for anything. Please
39
39
 
40
40
  ## Breaking changes
41
41
 
42
+ - The method vehicle.update(updateType) supports 3 different update types:
43
+ - 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.
44
+ - updateType=1: Full update (nearly all get-methods are called. The model images and the capabilitites are refreshed only every 2 hours.)
45
+ - updateType=2: Like updateType=0, but ignoring the nightly update reduction
46
+
47
+ - 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.
48
+
49
+ - 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 ....
50
+
42
51
  ## Thanks to
43
52
 
44
53
  - [RobinostLund](https://github.com/robinostlund/volkswagencarnet) for initial project for Volkswagen Carnet I was able to fork
45
54
  - [Farfar](https://github.com/Farfar) for modifications related to electric engines
46
55
  - [tanelvakker](https://github.com/tanelvakker) for modifications related to correct SPIN handling for various actions and using correct URLs also for MY2021
56
+ - [sdb9696](https://github.com/sdb9696) for the firebase-messaging package that is used in PyCupra with only minor modifications
47
57
 
48
58
  ### Example
49
59
 
@@ -52,6 +62,6 @@ When logged in the library will automatically create a vehicle object for every
52
62
  Method get_vehicles will fetch vehicle basic information and create Vehicle class objects for all associated vehicles in account.
53
63
  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.
54
64
 
55
- The file *cupra_credentials.json.demo* explains the data structure of the credentials file.
65
+ The file *pycupra_credentials.json.demo* explains the data structure of the credentials file.
56
66
 
57
67
 
@@ -14,11 +14,21 @@ No licence, public domain, no guarantees, feel free to use for anything. Please
14
14
 
15
15
  ## Breaking changes
16
16
 
17
+ - The method vehicle.update(updateType) supports 3 different update types:
18
+ - 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.
19
+ - updateType=1: Full update (nearly all get-methods are called. The model images and the capabilitites are refreshed only every 2 hours.)
20
+ - updateType=2: Like updateType=0, but ignoring the nightly update reduction
21
+
22
+ - 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.
23
+
24
+ - 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 ....
25
+
17
26
  ## Thanks to
18
27
 
19
28
  - [RobinostLund](https://github.com/robinostlund/volkswagencarnet) for initial project for Volkswagen Carnet I was able to fork
20
29
  - [Farfar](https://github.com/Farfar) for modifications related to electric engines
21
30
  - [tanelvakker](https://github.com/tanelvakker) for modifications related to correct SPIN handling for various actions and using correct URLs also for MY2021
31
+ - [sdb9696](https://github.com/sdb9696) for the firebase-messaging package that is used in PyCupra with only minor modifications
22
32
 
23
33
  ### Example
24
34
 
@@ -27,6 +37,6 @@ When logged in the library will automatically create a vehicle object for every
27
37
  Method get_vehicles will fetch vehicle basic information and create Vehicle class objects for all associated vehicles in account.
28
38
  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.
29
39
 
30
- The file *cupra_credentials.json.demo* explains the data structure of the credentials file.
40
+ The file *pycupra_credentials.json.demo* explains the data structure of the credentials file.
31
41
 
32
42
 
@@ -26,9 +26,10 @@ BRAND = 'cupra' # or 'seat' (Change it to 'seat' if you want to connect to the M
26
26
 
27
27
  PRINTRESPONSE = True
28
28
  INTERVAL = 5
29
- TOKEN_FILE_NAME_AND_PATH='./cupra_token.json'
30
- CREDENTIALS_FILE_NAME_AND_PATH='./cupra_credentials.json'
31
- ALL_ATTRIBUTES_FILE_NAME_AND_PATH='./cupra_all_attributes.txt'
29
+ TOKEN_FILE_NAME_AND_PATH='./pycupra_token.json'
30
+ CREDENTIALS_FILE_NAME_AND_PATH='./pycupra_credentials.json'
31
+ FIREBASE_CREDENTIALS_FILE_NAME_AND_PATH='./pycupra_firebase_credentials.json'
32
+ ALL_ATTRIBUTES_FILE_NAME_AND_PATH='./pycupra_all_attributes.txt'
32
33
 
33
34
 
34
35
  COMPONENTS = {
@@ -99,6 +100,7 @@ RESOURCES = [
99
100
  "service_inspection_distance",
100
101
  "slow_charge",
101
102
  "sunroof_closed",
103
+ "target_soc",
102
104
  "trip_last_average_auxillary_consumption",
103
105
  "trip_last_average_electric_consumption",
104
106
  "trip_last_average_fuel_consumption",
@@ -375,7 +377,7 @@ async def main():
375
377
  print('# Logging on to seat.cloud.vwgroup.com #')
376
378
  print('########################################')
377
379
  print(f"Initiating new session to Seat Cloud with {credentials.get('username')} as username")
378
- connection = Connection(session, BRAND, credentials.get('username'), credentials.get('password'), PRINTRESPONSE)
380
+ connection = Connection(session, BRAND, credentials.get('username'), credentials.get('password'), PRINTRESPONSE, nightlyUpdateReduction=False)
379
381
  print("Attempting to login to the Seat Cloud service")
380
382
  print(datetime.now())
381
383
  if await connection.doLogin(tokenFile=TOKEN_FILE_NAME_AND_PATH, apiKey=credentials.get('apiKey',None)):
@@ -394,6 +396,13 @@ async def main():
394
396
  instruments = set()
395
397
  for vehicle in connection.vehicles:
396
398
  txt = vehicle.vin
399
+ if vehicle == connection.vehicles[0]: # Firebase can only be activated for one vehicle. So we use it for the first one
400
+ newStatus = await vehicle.initialiseFirebase(FIREBASE_CREDENTIALS_FILE_NAME_AND_PATH, vehicle.update)
401
+ print('########################################')
402
+ print('# Initialisation of firebase #')
403
+ print(txt.center(40, '#'))
404
+ print(f"New status of firebase={newStatus}")
405
+
397
406
  print('')
398
407
  print('########################################')
399
408
  print('# Setting up dashboard #')
@@ -524,7 +533,7 @@ async def main():
524
533
  # Examples for using set functions:
525
534
 
526
535
  #await demo_set_charger(vehicle, action = "start") # action = "start" or "stop"
527
- #await demo_set_charger_current(vehicle, value='reduced') # value = 1-255/Maximum/Reduced (PHEV: 252 for reduced and 254 for max, EV: Maximum/Reduced)
536
+ #await demo_set_charger_current(vehicle, value='reduced') # value = 1-255/Maximum/Reduced (PHEV: 252 for reduced and 254 for max, EV: Maximum/Reduced)
528
537
 
529
538
  #await demo_set_climatisation(vehicle, action = "start", temp=18.0) # action = "auxilliary", "electric" or "off". spin is S-PIN and only needed for aux heating
530
539
  #await demo_set_climatisation_temp(vehicle, temp = 18.0) # temp = integer from 16 to 30
@@ -562,9 +571,15 @@ async def main():
562
571
  print('Export of all attributes successfully completed')
563
572
  else:
564
573
  print('Export of all attributes failed')
565
-
566
- print(f"Sleeping for {INTERVAL} seconds")
567
- await asyncio.sleep(INTERVAL)
574
+
575
+ if vehicle.firebaseStatus== 1: # firebase messaging activated
576
+ # Do an endless loop to wait and receive firebase messages
577
+ i=0
578
+ while True:
579
+ print(f"Sleeping for {6*INTERVAL} seconds")
580
+ await asyncio.sleep(6*INTERVAL)
581
+ i=i+1
582
+ _LOGGER.debug(f'Round {i}')
568
583
 
569
584
  exit
570
585
 
@@ -5,3 +5,4 @@ For more details and documentation, visit the github page at https://github.com/
5
5
  """
6
6
 
7
7
  from pycupra.connection import Connection
8
+
@@ -3,4 +3,4 @@ pycupra - A Python 3 library for interacting with the My Cupra/My Seat portal.
3
3
 
4
4
  For more details and documentation, visit the github page at https://github.com/WulfgarW/pycupra
5
5
  """
6
- __version__ = "0.0.15"
6
+ __version__ = "0.1.1"
@@ -46,7 +46,7 @@ from requests_oauthlib import OAuth2Session
46
46
  from oauthlib.oauth2.rfc6749.parameters import parse_authorization_code_response, parse_token_response, prepare_grant_uri
47
47
 
48
48
  from aiohttp import ClientSession, ClientTimeout
49
- from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT
49
+ from aiohttp.hdrs import METH_GET, METH_POST, METH_PUT, METH_DELETE
50
50
 
51
51
  from .const import (
52
52
  HEADERS_SESSION,
@@ -643,6 +643,8 @@ class Connection:
643
643
  res = {'status_code': response.status}
644
644
  elif response.status == 202 and method==METH_PUT:
645
645
  res = response
646
+ elif response.status == 200 and method==METH_DELETE:
647
+ res = response
646
648
  elif response.status >= 200 or response.status <= 300:
647
649
  # If this is a revoke token url, expect Content-Length 0 and return
648
650
  if int(response.headers.get('Content-Length', 0)) == 0 and 'revoke' in url:
@@ -759,7 +761,7 @@ class Connection:
759
761
  # Check if user needs to update consent
760
762
  try:
761
763
  await self.set_token(self._session_auth_brand)
762
- _LOGGER.debug('Achtung! getConsentInfo auskommentiert')
764
+ #_LOGGER.debug('Achtung! getConsentInfo auskommentiert')
763
765
  response = await self.get(eval(f"f'{API_MBB_STATUSDATA}'"))
764
766
  if response.get('profileCompleted','incomplete'):
765
767
  if response.get('profileCompleted',False):
@@ -1182,6 +1184,8 @@ class Connection:
1182
1184
  """Get charger data."""
1183
1185
  await self.set_token(self._session_auth_brand)
1184
1186
  try:
1187
+ chargingStatus = {}
1188
+ chargingInfo = {}
1185
1189
  response = await self.get(eval(f"f'{API_CHARGING}/status'"))
1186
1190
  if response.get('battery', {}):
1187
1191
  chargingStatus = response
@@ -1203,12 +1207,16 @@ class Connection:
1203
1207
  _LOGGER.warning(f'Could not fetch charging modes, HTTP status code: {response.get("status_code")}')
1204
1208
  else:
1205
1209
  _LOGGER.info('Unhandled error while trying to fetch charging modes')"""
1206
- data = {'charging': {
1207
- 'status': chargingStatus,
1208
- 'info' : chargingInfo,
1209
- #'modes' : chargingModes,
1210
- }
1211
- }
1210
+ if chargingStatus != {} and chargingInfo != {}:
1211
+ data = {'charging': {
1212
+ 'status': chargingStatus,
1213
+ 'info' : chargingInfo,
1214
+ #'modes' : chargingModes,
1215
+ }
1216
+ }
1217
+ else:
1218
+ _LOGGER.warning(f'getCharger() got no valid data. Returning None')
1219
+ return None
1212
1220
  return data
1213
1221
  except Exception as error:
1214
1222
  _LOGGER.warning(f'Could not fetch charger, error: {error}')
@@ -1321,7 +1329,7 @@ class Connection:
1321
1329
  if 'state' in k.lower():
1322
1330
  data['state'] = response.get(key).get(k)
1323
1331
  else:
1324
- if 'Id' in key:
1332
+ if 'Id' in key or 'id' in key:
1325
1333
  data['id'] = str(response.get(key))
1326
1334
  if 'State' in key:
1327
1335
  data['state'] = response.get(key)
@@ -1365,6 +1373,55 @@ class Connection:
1365
1373
  raise
1366
1374
  return False
1367
1375
 
1376
+ async def subscribe(self, vin, credentials):
1377
+ url = f'{APP_URI}/v2/subscriptions'
1378
+ deviceId = credentials.get('gcm',{}).get('app_id','')
1379
+ token = credentials.get('fcm',{}).get('registration',{}).get('token','')
1380
+
1381
+ data = {
1382
+ "deviceId": deviceId,
1383
+ "locale":"en_GB",
1384
+ "services":{"charging":True,"climatisation":True},
1385
+ "token": token,
1386
+ "userId": self._user_id,
1387
+ "vin":vin
1388
+ }
1389
+ return await self._setViaAPI(url, json=data)
1390
+
1391
+ async def deleteSubscription(self, credentials):
1392
+ await self.set_token(self._session_auth_brand)
1393
+ try:
1394
+ id = credentials.get('subscription',{}).get('id','')
1395
+ url = f'{APP_URI}/v1/subscriptions/{id}'
1396
+ response = await self._request(METH_DELETE, url)
1397
+ if response.status==200:
1398
+ _LOGGER.debug(f'Subscription {id} successfully deleted.')
1399
+ return response
1400
+ else:
1401
+ _LOGGER.debug(f'API did not successfully delete subscription.')
1402
+ raise SeatException(f'Invalid or no response for endpoint {url}')
1403
+ return response
1404
+ except aiohttp.client_exceptions.ClientResponseError as error:
1405
+ _LOGGER.debug(f'Request failed. Id: {id}, HTTP request headers: {self._session_headers}')
1406
+ if error.status == 401:
1407
+ _LOGGER.error('Unauthorized')
1408
+ elif error.status == 400:
1409
+ _LOGGER.error(f'Bad request')
1410
+ elif error.status == 429:
1411
+ _LOGGER.warning('Too many requests. Further requests can only be made after the end of next trip in order to protect your vehicles battery.')
1412
+ return 429
1413
+ elif error.status == 500:
1414
+ _LOGGER.error('Internal server error, server might be temporarily unavailable')
1415
+ elif error.status == 502:
1416
+ _LOGGER.error('Bad gateway, this function may not be implemented for this vehicle')
1417
+ else:
1418
+ _LOGGER.error(f'Unhandled HTTP exception: {error}')
1419
+ #return False
1420
+ except Exception as error:
1421
+ _LOGGER.error(f'Error: {error}')
1422
+ raise
1423
+ return False
1424
+
1368
1425
  async def setCharger(self, vin, baseurl, mode, data):
1369
1426
  """Start/Stop charger."""
1370
1427
  if mode in {'start', 'stop'}:
@@ -181,3 +181,14 @@ REQ_STATUS = {
181
181
  'vsr': 'fs-car/bs/vsr/v1/{BRAND}/{COUNTRY}/vehicles/{vin}/requests/{id}/jobstatus',
182
182
  'default': 'fs-car/bs/{section}/v1/{BRAND}/{COUNTRY}/vehicles/{vin}/requests/{id}/status'
183
183
  }
184
+
185
+ FCM_PROJECT_ID='ola-apps-prod'
186
+ FCM_APP_ID={
187
+ 'cupra': '1:530284123617:android:9b9ba5a87c7ffd37fbeea0',
188
+ 'seat': '1:530284123617:android:d6187613ac3d7b08fbeea0'
189
+ }
190
+ FCM_API_KEY='AIzaSyCoSp1zitklb1EDj5yQumN0VNhDizJQHLk'
191
+ FIREBASE_STATUS_NOT_INITIALISED= 0
192
+ FIREBASE_STATUS_ACTIVATED= 1
193
+ FIREBASE_STATUS_NOT_WANTED= -2
194
+ FIREBASE_STATUS_ACTIVATION_FAILED= -1
@@ -1037,6 +1037,13 @@ def create_instruments():
1037
1037
  unit="%",
1038
1038
  device_class="battery"
1039
1039
  ),
1040
+ Sensor(
1041
+ attr="target_soc",
1042
+ name="Target state of charge",
1043
+ icon="mdi:battery-positive",
1044
+ unit="%",
1045
+ device_class="battery"
1046
+ ),
1040
1047
  Sensor(
1041
1048
  attr="adblue_level",
1042
1049
  name="Adblue level",
@@ -0,0 +1,73 @@
1
+ import logging
2
+ import asyncio
3
+ import os
4
+ import json
5
+ import string
6
+ import secrets
7
+
8
+ from .firebase_messaging import FcmPushClient, FcmRegisterConfig
9
+
10
+ from .const import (
11
+ FCM_PROJECT_ID,
12
+ FCM_API_KEY,
13
+ FCM_APP_ID
14
+ )
15
+
16
+ _LOGGER = logging.getLogger(__name__)
17
+
18
+ class Firebase():
19
+ async def firebaseStart(self, onNotificationFunc, firebaseCredentialsFileName, brand='cupra'):
20
+ """ 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 =''
26
+
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
33
+
34
+
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()
42
+
43
+ def readFCMCredsFile(credsFile):
44
+ """ Reads the firebase cloud messaging credentials from file"""
45
+ try:
46
+ if os.path.isfile(credsFile):
47
+ with open(credsFile, "r") as f:
48
+ credString=f.read()
49
+ f.close()
50
+ creds=json.loads(credString)
51
+ return creds
52
+ else:
53
+ _LOGGER.debug(f'{credsFile} not found.')
54
+ return {}
55
+ except:
56
+ _LOGGER.warning('readFCMCredsFile() not successful.')
57
+ return ''
58
+
59
+ def writeFCMCredsFile(creds, firebaseCredentialsFileName):
60
+ """ Saves the firebase cloud messaging credentials to a file for future use """
61
+ try:
62
+ with open(firebaseCredentialsFileName, "w") as f:
63
+ f.write(json.dumps(creds))
64
+ f.close()
65
+ except Exception as e:
66
+ _LOGGER.warning(f'writeFCMCredsFile() not successful. Error: {e}')
67
+
68
+ async def onFCMCredentialsUpdated(creds, firebaseCredentialsFileName):
69
+ """ Is called from firebase-messaging package """
70
+ loop = asyncio.get_running_loop()
71
+ await loop.run_in_executor(None, writeFCMCredsFile, creds, firebaseCredentialsFileName)
72
+ #writeFCMCredsFile(creds, firebaseCredentialsFileName)
73
+
@@ -0,0 +1,20 @@
1
+ from .fcmpushclient import FcmPushClient, FcmPushClientConfig, FcmPushClientRunState
2
+ from .fcmregister import FcmRegisterConfig
3
+ from .proto.mcs_pb2 import ( # pylint: disable=no-name-in-module
4
+ Close,
5
+ DataMessageStanza,
6
+ HeartbeatAck,
7
+ HeartbeatPing,
8
+ IqStanza,
9
+ LoginRequest,
10
+ LoginResponse,
11
+ SelectiveAck,
12
+ StreamErrorStanza,
13
+ )
14
+
15
+ __all__ = [
16
+ "FcmPushClientConfig",
17
+ "FcmPushClient",
18
+ "FcmPushClientRunState",
19
+ "FcmRegisterConfig",
20
+ ]
@@ -0,0 +1,32 @@
1
+ """Constants module."""
2
+
3
+ GCM_REGISTER_URL = "https://android.clients.google.com/c2dm/register3"
4
+ GCM_CHECKIN_URL = "https://android.clients.google.com/checkin"
5
+ GCM_SERVER_KEY_BIN = (
6
+ b"\x04\x33\x94\xf7\xdf\xa1\xeb\xb1\xdc\x03\xa2\x5e\x15\x71\xdb\x48\xd3"
7
+ + b"\x2e\xed\xed\xb2\x34\xdb\xb7\x47\x3a\x0c\x8f\xc4\xcc\xe1\x6f\x3c"
8
+ + b"\x8c\x84\xdf\xab\xb6\x66\x3e\xf2\x0c\xd4\x8b\xfe\xe3\xf9\x76\x2f"
9
+ + b"\x14\x1c\x63\x08\x6a\x6f\x2d\xb1\x1a\x95\xb0\xce\x37\xc0\x9c\x6e"
10
+ )
11
+ # urlsafe b64 encoding of the binary key with = padding removed
12
+ GCM_SERVER_KEY_B64 = (
13
+ "BDOU99-h67HcA6JeFXHbSNMu7e2yNNu3RzoM"
14
+ + "j8TM4W88jITfq7ZmPvIM1Iv-4_l2LxQcYwhqby2xGpWwzjfAnG4"
15
+ )
16
+
17
+ FCM_SUBSCRIBE_URL = "https://fcm.googleapis.com/fcm/connect/subscribe/"
18
+ FCM_SEND_URL = "https://fcm.googleapis.com/fcm/send/"
19
+
20
+ FCM_API = "https://fcm.googleapis.com/v1/"
21
+ FCM_REGISTRATION = "https://fcmregistrations.googleapis.com/v1/"
22
+ FCM_INSTALLATION = "https://firebaseinstallations.googleapis.com/v1/"
23
+ AUTH_VERSION = "FIS_v2"
24
+ SDK_VERSION = "w:0.6.6"
25
+
26
+ DOORBELLS_ENDPOINT = "/clients_api/doorbots/{0}"
27
+
28
+ MCS_VERSION = 41
29
+ MCS_HOST = "mtalk.google.com"
30
+ MCS_PORT = 5228
31
+ MCS_SELECTIVE_ACK_ID = 12
32
+ MCS_STREAM_ACK_ID = 13