pycupra 0.0.6__py3-none-any.whl → 0.0.8__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/__version__.py +1 -1
- pycupra/connection.py +26 -1
- pycupra/dashboard.py +35 -3
- pycupra/vehicle.py +62 -14
- {pycupra-0.0.6.dist-info → pycupra-0.0.8.dist-info}/METADATA +1 -1
- pycupra-0.0.8.dist-info/RECORD +13 -0
- pycupra-0.0.6.dist-info/RECORD +0 -13
- {pycupra-0.0.6.dist-info → pycupra-0.0.8.dist-info}/WHEEL +0 -0
- {pycupra-0.0.6.dist-info → pycupra-0.0.8.dist-info}/licenses/LICENSE +0 -0
- {pycupra-0.0.6.dist-info → pycupra-0.0.8.dist-info}/top_level.txt +0 -0
pycupra/__version__.py
CHANGED
pycupra/connection.py
CHANGED
@@ -136,6 +136,10 @@ class Connection:
|
|
136
136
|
_LOGGER.info(f'Init PyCupra library, version {lib_version}')
|
137
137
|
_LOGGER.debug(f'Using service {self._session_base}')
|
138
138
|
|
139
|
+
self._sessionRequestCounter = 0
|
140
|
+
self._sessionRequestTimestamp = datetime.now(tz= None)
|
141
|
+
self._sessionRequestCounterHistory = {}
|
142
|
+
|
139
143
|
|
140
144
|
def _clear_cookies(self):
|
141
145
|
self._session._cookie_jar._cookies.clear()
|
@@ -604,6 +608,19 @@ class Connection:
|
|
604
608
|
"""Perform a HTTP query"""
|
605
609
|
if self._session_fulldebug:
|
606
610
|
_LOGGER.debug(f'HTTP {method} "{url}"')
|
611
|
+
try:
|
612
|
+
if datetime.now(tz=None).date() != self._sessionRequestTimestamp.date():
|
613
|
+
# A new day has begun. Store _sessionRequestCounter in history and reset timestamp and counter
|
614
|
+
self._sessionRequestCounterHistory[self._sessionRequestTimestamp.strftime('%Y-%m-%d')]=self._sessionRequestCounter
|
615
|
+
_LOGGER.info(f'History of the number of API calls:')
|
616
|
+
for key, value in self._sessionRequestCounterHistory.items:
|
617
|
+
_LOGGER.info(f' Date: {key}: {value} API calls')
|
618
|
+
|
619
|
+
self._sessionRequestTimestamp= datetime.now(tz=None)
|
620
|
+
self._sessionRequestCounter = 0
|
621
|
+
except Exception as e:
|
622
|
+
_LOGGER.error(f'Error while preparing output of API call history. Error: {e}')
|
623
|
+
self._sessionRequestCounter = self._sessionRequestCounter + 1
|
607
624
|
async with self._session.request(
|
608
625
|
method,
|
609
626
|
url,
|
@@ -694,7 +711,7 @@ class Connection:
|
|
694
711
|
for vehicle in self.vehicles:
|
695
712
|
if vehicle.vin not in update_list:
|
696
713
|
_LOGGER.debug(f'Adding {vehicle.vin} for data refresh')
|
697
|
-
update_list.append(vehicle.update())
|
714
|
+
update_list.append(vehicle.update(updateType=1))
|
698
715
|
else:
|
699
716
|
_LOGGER.debug(f'VIN {vehicle.vin} is already queued for data refresh')
|
700
717
|
|
@@ -884,6 +901,14 @@ class Connection:
|
|
884
901
|
_LOGGER.info('Unhandled error while trying to fetch mycar data')
|
885
902
|
except Exception as error:
|
886
903
|
_LOGGER.warning(f'Could not fetch mycar report, error: {error}')
|
904
|
+
if data=={}:
|
905
|
+
return False
|
906
|
+
return data
|
907
|
+
|
908
|
+
async def getMileage(self, vin, baseurl):
|
909
|
+
"""Get car information from customer profile, VIN, nickname, etc."""
|
910
|
+
await self.set_token(self._session_auth_brand)
|
911
|
+
data={}
|
887
912
|
try:
|
888
913
|
response = await self.get(eval(f"f'{API_MILEAGE}'"))
|
889
914
|
if response.get('mileageKm', {}):
|
pycupra/dashboard.py
CHANGED
@@ -444,9 +444,9 @@ class RequestFlash(Switch):
|
|
444
444
|
return dict(last_result = self.vehicle.honkandflash_action_status)
|
445
445
|
|
446
446
|
|
447
|
-
class
|
447
|
+
class RequestRefresh(Switch):
|
448
448
|
def __init__(self):
|
449
|
-
super().__init__(attr="refresh_data", name="
|
449
|
+
super().__init__(attr="refresh_data", name="Request wakeup vehicle", icon="mdi:car-connected")
|
450
450
|
|
451
451
|
@property
|
452
452
|
def state(self):
|
@@ -454,7 +454,7 @@ class RequestUpdate(Switch):
|
|
454
454
|
|
455
455
|
async def turn_on(self):
|
456
456
|
await self.vehicle.set_refresh()
|
457
|
-
await self.vehicle.update()
|
457
|
+
await self.vehicle.update(updateType=1) #full update after set_refresh
|
458
458
|
if self.callback is not None:
|
459
459
|
self.callback()
|
460
460
|
|
@@ -470,6 +470,31 @@ class RequestUpdate(Switch):
|
|
470
470
|
return dict(last_result = self.vehicle.refresh_action_status)
|
471
471
|
|
472
472
|
|
473
|
+
class RequestUpdate(Switch):
|
474
|
+
def __init__(self):
|
475
|
+
super().__init__(attr="update_data", name="Request full update", icon="mdi:timer-refresh")
|
476
|
+
|
477
|
+
@property
|
478
|
+
def state(self):
|
479
|
+
return False #self.vehicle.update
|
480
|
+
|
481
|
+
async def turn_on(self):
|
482
|
+
await self.vehicle.update(updateType=1) #full update after set_refresh
|
483
|
+
if self.callback is not None:
|
484
|
+
self.callback()
|
485
|
+
|
486
|
+
async def turn_off(self):
|
487
|
+
pass
|
488
|
+
|
489
|
+
@property
|
490
|
+
def assumed_state(self):
|
491
|
+
return False
|
492
|
+
|
493
|
+
#@property
|
494
|
+
#def attributes(self):
|
495
|
+
# return dict()
|
496
|
+
|
497
|
+
|
473
498
|
class ElectricClimatisation(Switch):
|
474
499
|
def __init__(self):
|
475
500
|
super().__init__(attr="electric_climatisation", name="Electric Climatisation", icon="mdi:radiator")
|
@@ -916,6 +941,7 @@ def create_instruments():
|
|
916
941
|
TrunkLock(),
|
917
942
|
RequestFlash(),
|
918
943
|
RequestHonkAndFlash(),
|
944
|
+
RequestRefresh(),
|
919
945
|
RequestUpdate(),
|
920
946
|
WindowHeater(),
|
921
947
|
BatteryClimatisation(),
|
@@ -1000,6 +1026,12 @@ def create_instruments():
|
|
1000
1026
|
icon="mdi:clock",
|
1001
1027
|
device_class="timestamp"
|
1002
1028
|
),
|
1029
|
+
Sensor(
|
1030
|
+
attr="last_full_update",
|
1031
|
+
name="Last full update",
|
1032
|
+
icon="mdi:clock",
|
1033
|
+
device_class="timestamp"
|
1034
|
+
),
|
1003
1035
|
Sensor(
|
1004
1036
|
attr="parking_time",
|
1005
1037
|
name="Parking time",
|
pycupra/vehicle.py
CHANGED
@@ -74,14 +74,17 @@ class Vehicle:
|
|
74
74
|
'transactionHistoryHonkFlash': {'active': False, 'reason': 'not supported'},
|
75
75
|
}
|
76
76
|
|
77
|
+
self._last_full_update = datetime.now(tz=None) - timedelta(seconds=1200)
|
78
|
+
|
79
|
+
|
77
80
|
#### API get and set functions ####
|
78
81
|
# Init and update vehicle data
|
79
82
|
async def discover(self):
|
80
83
|
"""Discover vehicle and initial data."""
|
81
|
-
await asyncio.gather(
|
82
|
-
|
83
|
-
|
84
|
-
)
|
84
|
+
#await asyncio.gather(
|
85
|
+
# self.get_basiccardata(),
|
86
|
+
# return_exceptions=True
|
87
|
+
#)
|
85
88
|
# Extract information of relevant capabilities
|
86
89
|
for capa in self._capabilities:
|
87
90
|
id=capa.get('id', '')
|
@@ -104,13 +107,13 @@ class Vehicle:
|
|
104
107
|
self._relevantCapabilties[id].update(data)
|
105
108
|
|
106
109
|
|
107
|
-
await self.get_trip_statistic()
|
110
|
+
await self.get_trip_statistic()
|
108
111
|
# Get URLs for model image
|
109
|
-
self._modelimages = await self.get_modelimageurl()
|
112
|
+
self._modelimages = await self.get_modelimageurl()
|
110
113
|
|
111
114
|
self._discovered = datetime.now()
|
112
115
|
|
113
|
-
async def update(self):
|
116
|
+
async def update(self, updateType=0):
|
114
117
|
"""Try to fetch data for all known API endpoints."""
|
115
118
|
# Update vehicle information if not discovered or stale information
|
116
119
|
if not self._discovered:
|
@@ -125,6 +128,21 @@ class Vehicle:
|
|
125
128
|
# Fetch all data if car is not deactivated
|
126
129
|
if not self.deactivated:
|
127
130
|
try:
|
131
|
+
# Data to be updated most often
|
132
|
+
await asyncio.gather(
|
133
|
+
self.get_charger(),
|
134
|
+
self.get_basiccardata(),
|
135
|
+
return_exceptions=True
|
136
|
+
)
|
137
|
+
|
138
|
+
fullUpdateExpired = datetime.now(tz=None) - timedelta(seconds= 1100)
|
139
|
+
if hasattr(self, '_last_full_update'):
|
140
|
+
_LOGGER.debug(f'last_full_update= {self._last_full_update}, fullUpdateExpired= {fullUpdateExpired}.')
|
141
|
+
if updateType!=1 and (hasattr(self, '_last_full_update') and self._last_full_update>fullUpdateExpired):
|
142
|
+
_LOGGER.debug(f'Just performed small update for vehicle with VIN {self.vin}.')
|
143
|
+
return True
|
144
|
+
|
145
|
+
# Data to be updated less often
|
128
146
|
await asyncio.gather(
|
129
147
|
self.get_preheater(),
|
130
148
|
self.get_climater(),
|
@@ -132,13 +150,15 @@ class Vehicle:
|
|
132
150
|
self.get_position(),
|
133
151
|
self.get_statusreport(),
|
134
152
|
self.get_vehicleHealthWarnings(),
|
135
|
-
self.get_charger(),
|
136
153
|
self.get_departure_timers(),
|
137
154
|
self.get_departure_profiles(),
|
138
|
-
self.
|
155
|
+
self.get_mileage(),
|
139
156
|
#self.get_modelimageurl(), #commented out, because getting the images discover() should be sufficient
|
140
157
|
return_exceptions=True
|
141
158
|
)
|
159
|
+
self._last_full_update = datetime.now(tz=None)
|
160
|
+
_LOGGER.debug(f'Performed full update for vehicle with VIN {self.vin}.')
|
161
|
+
_LOGGER.debug(f'So far about {self._connection._sessionRequestCounter} API calls since {self._connection._sessionRequestTimestamp}.')
|
142
162
|
except:
|
143
163
|
raise SeatException("Update failed")
|
144
164
|
return True
|
@@ -158,6 +178,12 @@ class Vehicle:
|
|
158
178
|
if data:
|
159
179
|
self._states.update(data)
|
160
180
|
|
181
|
+
async def get_mileage(self):
|
182
|
+
"""Fetch basic car data."""
|
183
|
+
data = await self._connection.getMileage(self.vin, self._apibase)
|
184
|
+
if data:
|
185
|
+
self._states.update(data)
|
186
|
+
|
161
187
|
async def get_preheater(self):
|
162
188
|
"""Fetch pre-heater data if function is enabled."""
|
163
189
|
_LOGGER.info('get_preheater() not implemented yet')
|
@@ -320,7 +346,7 @@ class Vehicle:
|
|
320
346
|
raise SeatInvalidRequestException('Remote start/stop of charger is not supported.')
|
321
347
|
if self._requests['batterycharge'].get('id', False):
|
322
348
|
timestamp = self._requests.get('batterycharge', {}).get('timestamp', datetime.now())
|
323
|
-
expired = datetime.now() - timedelta(minutes=
|
349
|
+
expired = datetime.now() - timedelta(minutes=1)
|
324
350
|
if expired > timestamp:
|
325
351
|
self._requests.get('batterycharge', {}).pop('id')
|
326
352
|
else:
|
@@ -574,7 +600,7 @@ class Vehicle:
|
|
574
600
|
raise SeatInvalidRequestException('Departure timers are not supported.')
|
575
601
|
if self._requests['departuretimer'].get('id', False):
|
576
602
|
timestamp = self._requests.get('departuretimer', {}).get('timestamp', datetime.now())
|
577
|
-
expired = datetime.now() - timedelta(minutes=
|
603
|
+
expired = datetime.now() - timedelta(minutes=1)
|
578
604
|
if expired > timestamp:
|
579
605
|
self._requests.get('departuretimer', {}).pop('id')
|
580
606
|
else:
|
@@ -848,7 +874,7 @@ class Vehicle:
|
|
848
874
|
raise SeatInvalidRequestException('Remote control of climatisation functions is not supported.')
|
849
875
|
if self._requests['climatisation'].get('id', False):
|
850
876
|
timestamp = self._requests.get('climatisation', {}).get('timestamp', datetime.now())
|
851
|
-
expired = datetime.now() - timedelta(minutes=
|
877
|
+
expired = datetime.now() - timedelta(minutes=1)
|
852
878
|
if expired > timestamp:
|
853
879
|
self._requests.get('climatisation', {}).pop('id')
|
854
880
|
else:
|
@@ -913,7 +939,7 @@ class Vehicle:
|
|
913
939
|
raise SeatInvalidRequestException('No parking heater support.')
|
914
940
|
if self._requests['preheater'].get('id', False):
|
915
941
|
timestamp = self._requests.get('preheater', {}).get('timestamp', datetime.now())
|
916
|
-
expired = datetime.now() - timedelta(minutes=
|
942
|
+
expired = datetime.now() - timedelta(minutes=1)
|
917
943
|
if expired > timestamp:
|
918
944
|
self._requests.get('preheater', {}).pop('id')
|
919
945
|
else:
|
@@ -1053,7 +1079,7 @@ class Vehicle:
|
|
1053
1079
|
raise SeatInvalidRequestException('Data refresh is not supported.')
|
1054
1080
|
if self._requests['refresh'].get('id', False):
|
1055
1081
|
timestamp = self._requests.get('refresh', {}).get('timestamp', datetime.now() - timedelta(minutes=5))
|
1056
|
-
expired = datetime.now() - timedelta(minutes=
|
1082
|
+
expired = datetime.now() - timedelta(minutes=1)
|
1057
1083
|
if expired > timestamp:
|
1058
1084
|
self._requests.get('refresh', {}).pop('id')
|
1059
1085
|
else:
|
@@ -1228,6 +1254,18 @@ class Vehicle:
|
|
1228
1254
|
if 'updatedAt' in self.attrs.get('status', {}):
|
1229
1255
|
return True
|
1230
1256
|
|
1257
|
+
# Update status
|
1258
|
+
@property
|
1259
|
+
def last_full_update(self):
|
1260
|
+
"""Return when the last full update for the vehicle took place."""
|
1261
|
+
return self._last_full_update.astimezone(tz=None)
|
1262
|
+
|
1263
|
+
@property
|
1264
|
+
def is_last_full_update_supported(self):
|
1265
|
+
"""Return when last full update for vehicle took place."""
|
1266
|
+
if hasattr(self,'_last_full_update'):
|
1267
|
+
return True
|
1268
|
+
|
1231
1269
|
# Service information
|
1232
1270
|
@property
|
1233
1271
|
def distance(self):
|
@@ -2683,6 +2721,16 @@ class Vehicle:
|
|
2683
2721
|
if self._connectivities.get('mode', '') == 'online':
|
2684
2722
|
return True
|
2685
2723
|
|
2724
|
+
@property
|
2725
|
+
def update_data(self):
|
2726
|
+
"""Get state of data update"""
|
2727
|
+
return False
|
2728
|
+
|
2729
|
+
@property
|
2730
|
+
def is_update_data_supported(self):
|
2731
|
+
"""Data update is supported."""
|
2732
|
+
return True
|
2733
|
+
|
2686
2734
|
# Honk and flash
|
2687
2735
|
@property
|
2688
2736
|
def request_honkandflash(self):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pycupra
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.8
|
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
|
@@ -0,0 +1,13 @@
|
|
1
|
+
pycupra/__init__.py,sha256=VPzUfKd5mBFD1UERNV61FbGHih5dQPupLgIfYtmIUi4,230
|
2
|
+
pycupra/__version__.py,sha256=g845Cq_z0hjlwG9RG4nM9vit4t_cEbb5HkAMZ7Iav3Y,207
|
3
|
+
pycupra/connection.py,sha256=fNjyrj6nBLOfEpKcygDs47UFlWjmR4tgJa1KPLLNZLU,82411
|
4
|
+
pycupra/const.py,sha256=VEYH8TUsJGJwBwloaajwoElYd0qxE7oesvoagvDdE-4,10161
|
5
|
+
pycupra/dashboard.py,sha256=Dqs4qDF-rEoYXoS7NrNsvRMsCGzoAjVUEbfTSOdDAXo,41310
|
6
|
+
pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
|
7
|
+
pycupra/utilities.py,sha256=cH4MiIzT2WlHgmnl_E7rR0R5LvCXfDNvirJolct50V8,2563
|
8
|
+
pycupra/vehicle.py,sha256=J5jUAseVTtb9HK0-RvCi-VzkJ1z0h4Phn_Tgno6Sgzk,122420
|
9
|
+
pycupra-0.0.8.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
10
|
+
pycupra-0.0.8.dist-info/METADATA,sha256=Z8QMsbcu3IXFWgeNLKTk91sGirawTdhXhEoCqFvhAPs,2578
|
11
|
+
pycupra-0.0.8.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
12
|
+
pycupra-0.0.8.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
|
13
|
+
pycupra-0.0.8.dist-info/RECORD,,
|
pycupra-0.0.6.dist-info/RECORD
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
pycupra/__init__.py,sha256=VPzUfKd5mBFD1UERNV61FbGHih5dQPupLgIfYtmIUi4,230
|
2
|
-
pycupra/__version__.py,sha256=YbGN0knQ3fpcD8GGO6OA7ZBYa-fQ4unLaw-NTYREVn8,207
|
3
|
-
pycupra/connection.py,sha256=4bcaHn6AwAAY9e3MfVwlPMQzKJZQo_BZttts0lubnro,81120
|
4
|
-
pycupra/const.py,sha256=VEYH8TUsJGJwBwloaajwoElYd0qxE7oesvoagvDdE-4,10161
|
5
|
-
pycupra/dashboard.py,sha256=difLM3R2uXUrVslUjqzH8nN6WPJA-u26rHlGUU6W8Oo,40454
|
6
|
-
pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
|
7
|
-
pycupra/utilities.py,sha256=cH4MiIzT2WlHgmnl_E7rR0R5LvCXfDNvirJolct50V8,2563
|
8
|
-
pycupra/vehicle.py,sha256=vlSuvrspX_I1RlS8KoZkN09u5cCNNdcIslsA0xPUuqA,120442
|
9
|
-
pycupra-0.0.6.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
10
|
-
pycupra-0.0.6.dist-info/METADATA,sha256=k-diSYUQOySb2FxopmNeWMOXqf_FQG1A5yGwnMpo03M,2578
|
11
|
-
pycupra-0.0.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
12
|
-
pycupra-0.0.6.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
|
13
|
-
pycupra-0.0.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|