pycupra 0.1.7__py3-none-any.whl → 0.1.9__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 +25 -3
- pycupra/const.py +1 -1
- pycupra/dashboard.py +46 -16
- pycupra/firebase.py +3 -3
- pycupra/firebase_messaging/fcmpushclient.py +7 -2
- pycupra/vehicle.py +157 -81
- {pycupra-0.1.7.dist-info → pycupra-0.1.9.dist-info}/METADATA +1 -1
- {pycupra-0.1.7.dist-info → pycupra-0.1.9.dist-info}/RECORD +12 -12
- {pycupra-0.1.7.dist-info → pycupra-0.1.9.dist-info}/WHEEL +0 -0
- {pycupra-0.1.7.dist-info → pycupra-0.1.9.dist-info}/licenses/LICENSE +0 -0
- {pycupra-0.1.7.dist-info → pycupra-0.1.9.dist-info}/top_level.txt +0 -0
pycupra/__version__.py
CHANGED
pycupra/connection.py
CHANGED
@@ -98,6 +98,7 @@ from .const import (
|
|
98
98
|
API_DESTINATION,
|
99
99
|
|
100
100
|
PUBLIC_MODEL_IMAGES_SERVER,
|
101
|
+
FIREBASE_STATUS_NOT_INITIALISED,
|
101
102
|
)
|
102
103
|
|
103
104
|
version_info >= (3, 0) or exit('Python 3 required')
|
@@ -109,13 +110,14 @@ TIMEOUT = timedelta(seconds=90)
|
|
109
110
|
class Connection:
|
110
111
|
""" Connection to Connect services """
|
111
112
|
# Init connection class
|
112
|
-
def __init__(self, session, brand='cupra', username='', password='', fulldebug=False, nightlyUpdateReduction=False, anonymise=True, **optional):
|
113
|
+
def __init__(self, session, brand='cupra', username='', password='', fulldebug=False, nightlyUpdateReduction=False, anonymise=True, tripStatisticsStartDate=None, **optional):
|
113
114
|
""" Initialize """
|
114
115
|
self._session = session
|
115
116
|
self._lock = asyncio.Lock()
|
116
117
|
self._session_fulldebug = fulldebug
|
117
118
|
self._session_nightlyUpdateReduction = nightlyUpdateReduction
|
118
119
|
self._session_anonymise = anonymise
|
120
|
+
self._session_tripStatisticsStartDate = tripStatisticsStartDate
|
119
121
|
self._session_headers = HEADERS_SESSION.get(brand).copy()
|
120
122
|
self._session_base = BASE_SESSION
|
121
123
|
self._session_auth_headers = HEADERS_AUTH.copy()
|
@@ -560,8 +562,10 @@ class Connection:
|
|
560
562
|
for v in self.vehicles:
|
561
563
|
_LOGGER.debug(self.anonymise(f'Calling stopFirebase() for vehicle {v.vin}'))
|
562
564
|
newStatus = await v.stopFirebase()
|
563
|
-
if newStatus !=
|
565
|
+
if newStatus != FIREBASE_STATUS_NOT_INITIALISED:
|
564
566
|
_LOGGER.debug(self.anonymise(f'stopFirebase() not successful for vehicle {v.vin}'))
|
567
|
+
# Although stopFirebase() was not successful, the firebase status is reset to FIREBASE_STATUS_NOT_INITIALISED to allow a new initialisation
|
568
|
+
v.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
|
565
569
|
await self.logout()
|
566
570
|
|
567
571
|
async def logout(self):
|
@@ -636,7 +640,12 @@ class Connection:
|
|
636
640
|
async def _request(self, method, url, **kwargs):
|
637
641
|
"""Perform a HTTP query"""
|
638
642
|
if self._session_fulldebug:
|
639
|
-
|
643
|
+
argsString =''
|
644
|
+
if len(kwargs)>0:
|
645
|
+
argsString = 'with '
|
646
|
+
for k, val in kwargs.items():
|
647
|
+
argsString = argsString + f"{k}=\'{val}\' "
|
648
|
+
_LOGGER.debug(self.anonymise(f'HTTP {method} "{url}" {argsString}'))
|
640
649
|
try:
|
641
650
|
if datetime.now(tz=None).date() != self._sessionRequestTimestamp.date():
|
642
651
|
# A new day has begun. Store _sessionRequestCounter in history and reset timestamp and counter
|
@@ -701,6 +710,9 @@ class Connection:
|
|
701
710
|
if self._session_fulldebug:
|
702
711
|
if 'image/png' in response.headers.get('Content-Type', ''):
|
703
712
|
_LOGGER.debug(self.anonymise(f'Request for "{url}" returned with status code [{response.status}]. Not showing response for Content-Type image/png.'))
|
713
|
+
elif method==METH_PUT or method==METH_DELETE:
|
714
|
+
# deepcopy() of res can produce errors, if res is the API response on PUT or DELETE
|
715
|
+
_LOGGER.debug(f'Request for "{self.anonymise(url)}" returned with status code [{response.status}]. Not showing response for http {method}')
|
704
716
|
else:
|
705
717
|
_LOGGER.debug(self.anonymise(f'Request for "{url}" returned with status code [{response.status}], response: {self.anonymise(deepcopy(res))}'))
|
706
718
|
else:
|
@@ -1080,6 +1092,12 @@ class Connection:
|
|
1080
1092
|
async def getTripStatistics(self, vin, baseurl, supportsCyclicTrips):
|
1081
1093
|
"""Get short term and cyclic trip statistics."""
|
1082
1094
|
await self.set_token(self._session_auth_brand)
|
1095
|
+
if self._session_tripStatisticsStartDate==None:
|
1096
|
+
# If connection was not initialised with parameter tripStatisticsStartDate, then 360 day is used for the CYCLIC trips and 90 days for the SHORT trips
|
1097
|
+
# (This keeps the statistics shorter in Home Assistant)
|
1098
|
+
startDate = (datetime.now() - timedelta(days= 360)).strftime('%Y-%m-%d')
|
1099
|
+
else:
|
1100
|
+
startDate = self._session_tripStatisticsStartDate
|
1083
1101
|
try:
|
1084
1102
|
data={'tripstatistics': {}}
|
1085
1103
|
if supportsCyclicTrips:
|
@@ -1094,6 +1112,10 @@ class Connection:
|
|
1094
1112
|
else:
|
1095
1113
|
_LOGGER.info(f'Vehicle does not support cyclic trips.')
|
1096
1114
|
dataType='SHORT'
|
1115
|
+
if self._session_tripStatisticsStartDate==None:
|
1116
|
+
# If connection was not initialised with parameter tripStatisticsStartDate, then 360 day is used for the CYCLIC trips and 90 days for the SHORT trips
|
1117
|
+
# (This keeps the statistics shorter in Home Assistant)
|
1118
|
+
startDate = (datetime.now() - timedelta(days= 90)).strftime('%Y-%m-%d')
|
1097
1119
|
response = await self.get(eval(f"f'{API_TRIP}'"))
|
1098
1120
|
if response.get('data', []):
|
1099
1121
|
data['tripstatistics']['short']= response.get('data', [])
|
pycupra/const.py
CHANGED
@@ -138,7 +138,7 @@ API_DEPARTURE_TIMERS = '{baseurl}/v1/vehicles/{vin}/departure-timers'
|
|
138
138
|
API_DEPARTURE_PROFILES = '{baseurl}/v1/vehicles/{vin}/departure/profiles' # Departure profiles
|
139
139
|
API_POSITION = '{baseurl}/v1/vehicles/{vin}/parkingposition' # Position data
|
140
140
|
API_POS_TO_ADDRESS= 'https://maps.googleapis.com/maps/api/directions/json?origin={lat},{lon}&destination={lat},{lon}&traffic_model=best_guess&departure_time=now&language=de&key={apiKeyForGoogle}&mode=driving'
|
141
|
-
API_TRIP = '{baseurl}/v1/vehicles/{vin}/driving-data/{dataType}?from=
|
141
|
+
API_TRIP = '{baseurl}/v1/vehicles/{vin}/driving-data/{dataType}?from={startDate}T00:00:00Z&to=2099-12-31T09:59:01Z' # Trip statistics (whole history) SHORT/LONG/CYCLIC (WEEK only with from)
|
142
142
|
API_MILEAGE = '{baseurl}/v1/vehicles/{vin}/mileage' # Total km etc
|
143
143
|
API_MAINTENANCE = '{baseurl}/v1/vehicles/{vin}/maintenance' # Inspection information
|
144
144
|
API_MEASUREMENTS = '{baseurl}/v1/vehicles/{vin}/measurements/engines' # ???
|
pycupra/dashboard.py
CHANGED
@@ -455,7 +455,7 @@ class RequestRefresh(Switch):
|
|
455
455
|
async def turn_on(self):
|
456
456
|
_LOGGER.debug('User has called RequestRefresh().')
|
457
457
|
await self.vehicle.set_refresh()
|
458
|
-
await self.vehicle.update(updateType=1) #full update after set_refresh
|
458
|
+
#await self.vehicle.update(updateType=1) #full update after set_refresh
|
459
459
|
if self.callback is not None:
|
460
460
|
self.callback()
|
461
461
|
|
@@ -776,11 +776,12 @@ class DepartureTimer1(Switch):
|
|
776
776
|
|
777
777
|
@property
|
778
778
|
def state(self):
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
779
|
+
if self.vehicle.departure1 != None:
|
780
|
+
status = self.vehicle.departure1.get("enabled", "")
|
781
|
+
if status:
|
782
|
+
return True
|
783
|
+
#else:
|
784
|
+
return False
|
784
785
|
|
785
786
|
async def turn_on(self):
|
786
787
|
await self.vehicle.set_timer_active(id=1, action="on")
|
@@ -808,11 +809,12 @@ class DepartureTimer2(Switch):
|
|
808
809
|
|
809
810
|
@property
|
810
811
|
def state(self):
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
812
|
+
if self.vehicle.departure2 != None:
|
813
|
+
status = self.vehicle.departure2.get("enabled", "")
|
814
|
+
if status:
|
815
|
+
return True
|
816
|
+
#else:
|
817
|
+
return False
|
816
818
|
|
817
819
|
async def turn_on(self):
|
818
820
|
await self.vehicle.set_timer_active(id=2, action="on")
|
@@ -839,11 +841,12 @@ class DepartureTimer3(Switch):
|
|
839
841
|
|
840
842
|
@property
|
841
843
|
def state(self):
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
844
|
+
if self.vehicle.departure3 != None:
|
845
|
+
status = self.vehicle.departure3.get("enabled", "")
|
846
|
+
if status:
|
847
|
+
return True
|
848
|
+
#else:
|
849
|
+
return False
|
847
850
|
|
848
851
|
async def turn_on(self):
|
849
852
|
await self.vehicle.set_timer_active(id=3, action="on")
|
@@ -1002,6 +1005,32 @@ class ChargingState(BinarySensor):
|
|
1002
1005
|
attr['mode']=mode
|
1003
1006
|
return attr
|
1004
1007
|
|
1008
|
+
class AreaAlarm(BinarySensor):
|
1009
|
+
def __init__(self):
|
1010
|
+
super().__init__(attr="area_alarm", name="Area alarm", icon="mdi:alarm-light", device_class=None)
|
1011
|
+
|
1012
|
+
@property
|
1013
|
+
def state(self):
|
1014
|
+
return self.vehicle.area_alarm
|
1015
|
+
|
1016
|
+
@property
|
1017
|
+
def assumed_state(self):
|
1018
|
+
return False
|
1019
|
+
|
1020
|
+
@property
|
1021
|
+
def attributes(self):
|
1022
|
+
attr = {}
|
1023
|
+
type = self.vehicle.attrs.get('areaAlarm', {}).get('type', '')
|
1024
|
+
zones = self.vehicle.attrs.get('areaAlarm', {}).get('zones', [])
|
1025
|
+
timestamp = self.vehicle.attrs.get('areaAlarm', {}).get('timestamp', 0)
|
1026
|
+
if type != '':
|
1027
|
+
attr['type']=type
|
1028
|
+
if len(zones) > 0:
|
1029
|
+
attr['zone']=zones[0]
|
1030
|
+
if timestamp != 0:
|
1031
|
+
attr['timestamp']=timestamp
|
1032
|
+
return attr
|
1033
|
+
|
1005
1034
|
def create_instruments():
|
1006
1035
|
return [
|
1007
1036
|
Position(),
|
@@ -1030,6 +1059,7 @@ def create_instruments():
|
|
1030
1059
|
DepartureProfile2(),
|
1031
1060
|
DepartureProfile3(),
|
1032
1061
|
ChargingState(),
|
1062
|
+
AreaAlarm(),
|
1033
1063
|
Sensor(
|
1034
1064
|
attr="distance",
|
1035
1065
|
name="Odometer",
|
pycupra/firebase.py
CHANGED
@@ -43,7 +43,7 @@ class Firebase():
|
|
43
43
|
await asyncio.sleep(5)
|
44
44
|
return self._pushClient.is_started()
|
45
45
|
except Exception as e:
|
46
|
-
_LOGGER.error('Error in firebaseStart. Error: {e}')
|
46
|
+
_LOGGER.error(f'Error in firebaseStart. Error: {e}')
|
47
47
|
return False
|
48
48
|
|
49
49
|
async def firebaseStop(self):
|
@@ -54,7 +54,7 @@ class Firebase():
|
|
54
54
|
self._pushClient = None
|
55
55
|
return True
|
56
56
|
except Exception as e:
|
57
|
-
_LOGGER.error('Error in firebaseStop. Error: {e}')
|
57
|
+
_LOGGER.error(f'Error in firebaseStop. Error: {e}')
|
58
58
|
return False
|
59
59
|
|
60
60
|
def readFCMCredsFile(credsFile):
|
@@ -70,7 +70,7 @@ def readFCMCredsFile(credsFile):
|
|
70
70
|
_LOGGER.debug(f'{credsFile} not found.')
|
71
71
|
return {}
|
72
72
|
except Exception as e:
|
73
|
-
_LOGGER.warning('readFCMCredsFile() not successful. Error: {e}')
|
73
|
+
_LOGGER.warning(f'readFCMCredsFile() not successful. Error: {e}')
|
74
74
|
return ''
|
75
75
|
|
76
76
|
def writeFCMCredsFile(creds, firebaseCredentialsFileName):
|
@@ -92,10 +92,10 @@ class FcmPushClientConfig: # pylint:disable=too-many-instance-attributes
|
|
92
92
|
"""Class to provide configuration to
|
93
93
|
:class:`firebase_messaging.FcmPushClientConfig`.FcmPushClient."""
|
94
94
|
|
95
|
-
server_heartbeat_interval: int | None =
|
95
|
+
server_heartbeat_interval: int | None = 30 # original value was 10
|
96
96
|
"""Time in seconds to request the server to send heartbeats"""
|
97
97
|
|
98
|
-
client_heartbeat_interval: int | None =
|
98
|
+
client_heartbeat_interval: int | None = 40 # original value was 20
|
99
99
|
"""Time in seconds to send heartbeats to the server"""
|
100
100
|
|
101
101
|
send_selective_acknowledgements: bool = True
|
@@ -218,6 +218,7 @@ class FcmPushClient: # pylint:disable=too-many-instance-attributes
|
|
218
218
|
or (self.stopping_lock and self.stopping_lock.locked())
|
219
219
|
or not self.do_listen
|
220
220
|
):
|
221
|
+
_logger.debug(f"In _reset. reset_lock={self.reset_lock}, reset_lock.locked={self.reset_lock.locked()}, stopping_lock={self.stopping_lock}, stopping_lock.locked={self.stopping_lock.locked()}, do_listen={self.do_listen}")
|
221
222
|
return
|
222
223
|
|
223
224
|
async with self.reset_lock: # type: ignore[union-attr]
|
@@ -725,7 +726,10 @@ class FcmPushClient: # pylint:disable=too-many-instance-attributes
|
|
725
726
|
else:
|
726
727
|
_logger.exception("Unexpected exception during read\n")
|
727
728
|
if self._try_increment_error_count(ErrorType.CONNECTION):
|
729
|
+
_logger.debug("Calling reset()\n")
|
728
730
|
await self._reset()
|
731
|
+
else:
|
732
|
+
_logger.debug("Not calling reset()\n")
|
729
733
|
except Exception as ex:
|
730
734
|
_logger.error(
|
731
735
|
"Unknown error: %s, shutting down FcmPushClient.\n%s",
|
@@ -805,3 +809,4 @@ class FcmPushClient: # pylint:disable=too-many-instance-attributes
|
|
805
809
|
dms.persistent_id = persistent_id
|
806
810
|
|
807
811
|
# Not supported yet
|
812
|
+
|
pycupra/vehicle.py
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
import re
|
5
5
|
import logging
|
6
6
|
import asyncio
|
7
|
+
import json
|
7
8
|
|
8
9
|
from copy import deepcopy
|
9
10
|
from datetime import datetime, timedelta, timezone
|
@@ -72,7 +73,6 @@ class Vehicle:
|
|
72
73
|
self._relevantCapabilties = {
|
73
74
|
'measurements': {'active': False, 'reason': 'not supported', },
|
74
75
|
'climatisation': {'active': False, 'reason': 'not supported'},
|
75
|
-
#'parkingInformation': {'active': False, 'reason': 'not supported'},
|
76
76
|
'tripStatistics': {'active': False, 'reason': 'not supported', 'supportsCyclicTrips': False},
|
77
77
|
'vehicleHealthInspection': {'active': False, 'reason': 'not supported'},
|
78
78
|
'vehicleHealthWarnings': {'active': False, 'reason': 'not supported'},
|
@@ -95,6 +95,7 @@ class Vehicle:
|
|
95
95
|
self._last_get_charger = datetime.now(tz=None) - timedelta(seconds=600)
|
96
96
|
self._last_get_climater = datetime.now(tz=None) - timedelta(seconds=600)
|
97
97
|
self._last_get_mileage = datetime.now(tz=None) - timedelta(seconds=600)
|
98
|
+
self._last_get_position = datetime.now(tz=None) - timedelta(seconds=600)
|
98
99
|
|
99
100
|
|
100
101
|
#### API get and set functions ####
|
@@ -131,8 +132,7 @@ class Vehicle:
|
|
131
132
|
self._relevantCapabilties[id].update(data)
|
132
133
|
|
133
134
|
|
134
|
-
|
135
|
-
|
135
|
+
|
136
136
|
# Get URLs for model image
|
137
137
|
self._modelimages = await self.get_modelimageurl()
|
138
138
|
|
@@ -148,11 +148,16 @@ class Vehicle:
|
|
148
148
|
hourago = datetime.now() - timedelta(hours = 2)
|
149
149
|
if self._discovered < hourago:
|
150
150
|
await self.discover()
|
151
|
-
#_LOGGER.debug('Achtung! self.discover() auskommentiert')
|
152
151
|
|
153
152
|
# Fetch all data if car is not deactivated
|
154
153
|
if not self.deactivated:
|
155
154
|
try:
|
155
|
+
if self.attrs.get('areaAlarm', {}) !={}:
|
156
|
+
# Delete an area alarm if it is older than 900 seconds
|
157
|
+
alarmTimestamp = self.attrs.get('areaAlarm', {}).get('timestamp', 0)
|
158
|
+
if alarmTimestamp < datetime.now(tz=None) - timedelta(seconds= 900):
|
159
|
+
self.attrs.pop("areaAlarm")
|
160
|
+
|
156
161
|
if self.firebaseStatus == FIREBASE_STATUS_ACTIVATED:
|
157
162
|
# Check, if fcmpushclient still started
|
158
163
|
if not self.firebase._pushClient.is_started():
|
@@ -170,6 +175,28 @@ class Vehicle:
|
|
170
175
|
else:
|
171
176
|
fullUpdateExpired = datetime.now(tz=None) - timedelta(seconds= 1100)
|
172
177
|
|
178
|
+
if self.firebaseStatus == FIREBASE_STATUS_ACTIVATION_STOPPED:
|
179
|
+
# Trying to activate firebase connection again
|
180
|
+
"""_LOGGER.debug(f'As firebase status={self.firebaseStatus}, fcmpushclient.start() is called.')
|
181
|
+
await self.firebase._pushClient.start()
|
182
|
+
#await asyncio.sleep(5)
|
183
|
+
if self.firebase._pushClient.is_started():
|
184
|
+
self.firebaseStatus = FIREBASE_STATUS_ACTIVATED
|
185
|
+
_LOGGER.debug(f'Successfully restarted push client. New firebase status={self.firebaseStatus}')
|
186
|
+
else:
|
187
|
+
_LOGGER.warning(f'Restart of push client failed. Firebase status={self.firebaseStatus}')"""
|
188
|
+
newStatus = await self.stopFirebase()
|
189
|
+
if newStatus != FIREBASE_STATUS_NOT_INITIALISED:
|
190
|
+
_LOGGER.debug(f'stopFirebase() not successful.')
|
191
|
+
# Although stopFirebase() was not successful, the firebase status is reset to FIREBASE_STATUS_NOT_INITIALISED to allow a new initialisation
|
192
|
+
self.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
|
193
|
+
newStatus = await self.initialiseFirebase(self._firebaseCredentialsFileName, self.updateCallback)
|
194
|
+
if newStatus == FIREBASE_STATUS_ACTIVATED:
|
195
|
+
_LOGGER.debug(f'Reinitialisation of firebase successful.New firebase status={self.firebaseStatus}.')
|
196
|
+
else:
|
197
|
+
self.firebaseStatus = FIREBASE_STATUS_ACTIVATION_STOPPED
|
198
|
+
_LOGGER.warning(f'Reinitialisation of firebase failed. New firebase status={self.firebaseStatus}.')
|
199
|
+
|
173
200
|
if self._connection._session_nightlyUpdateReduction:
|
174
201
|
# nightlyUpdateReduction is activated
|
175
202
|
if datetime.now(tz=None).hour<5 or datetime.now(tz=None).hour>=22:
|
@@ -198,16 +225,6 @@ class Vehicle:
|
|
198
225
|
if self.firebaseStatus != FIREBASE_STATUS_ACTIVATED:
|
199
226
|
await self.get_mileage()
|
200
227
|
|
201
|
-
if self.firebaseStatus == FIREBASE_STATUS_ACTIVATION_STOPPED:
|
202
|
-
# Trying to activate firebase connection again
|
203
|
-
await self.firebase._pushClient.start()
|
204
|
-
#await asyncio.sleep(5)
|
205
|
-
if self.firebase._pushClient.is_started():
|
206
|
-
self.firebaseStatus = FIREBASE_STATUS_ACTIVATED
|
207
|
-
_LOGGER.debug(f'Successfully restarted push client. New firebase status ={self.firebaseStatus}')
|
208
|
-
else:
|
209
|
-
_LOGGER.debug(f'Restart of push client failed. Firebase status ={self.firebaseStatus}')
|
210
|
-
|
211
228
|
|
212
229
|
await asyncio.gather(
|
213
230
|
#self.get_statusreport(),
|
@@ -244,6 +261,10 @@ class Vehicle:
|
|
244
261
|
data = await self._connection.getBasicCarData(self.vin, self._apibase)
|
245
262
|
if data:
|
246
263
|
self._states.update(data)
|
264
|
+
return True
|
265
|
+
else:
|
266
|
+
_LOGGER.debug('Could not fetch basic car data')
|
267
|
+
return False
|
247
268
|
|
248
269
|
async def get_mileage(self):
|
249
270
|
"""Fetch basic car data."""
|
@@ -251,6 +272,10 @@ class Vehicle:
|
|
251
272
|
if data:
|
252
273
|
self._states.update(data)
|
253
274
|
self._last_get_mileage = datetime.now(tz=None)
|
275
|
+
return True
|
276
|
+
else:
|
277
|
+
_LOGGER.debug('Could not fetch mileage data')
|
278
|
+
return False
|
254
279
|
|
255
280
|
async def get_preheater(self):
|
256
281
|
"""Fetch pre-heater data if function is enabled."""
|
@@ -272,8 +297,10 @@ class Vehicle:
|
|
272
297
|
if data:
|
273
298
|
self._states.update(data)
|
274
299
|
self._last_get_climater = datetime.now(tz=None)
|
300
|
+
return True
|
275
301
|
else:
|
276
302
|
_LOGGER.debug('Could not fetch climater data')
|
303
|
+
return False
|
277
304
|
#else:
|
278
305
|
# self._requests.pop('climatisation', None)
|
279
306
|
|
@@ -283,8 +310,10 @@ class Vehicle:
|
|
283
310
|
data = await self._connection.getTripStatistics(self.vin, self._apibase, self._relevantCapabilties['tripStatistics'].get('supportsCyclicTrips', False))
|
284
311
|
if data:
|
285
312
|
self._states.update(data)
|
313
|
+
return True
|
286
314
|
else:
|
287
315
|
_LOGGER.debug('Could not fetch trip statistics')
|
316
|
+
return False
|
288
317
|
|
289
318
|
async def get_position(self):
|
290
319
|
"""Fetch position data if function is enabled."""
|
@@ -301,24 +330,21 @@ class Vehicle:
|
|
301
330
|
except:
|
302
331
|
pass
|
303
332
|
self._states.update(data)
|
333
|
+
self._last_get_position = datetime.now(tz=None)
|
334
|
+
return True
|
304
335
|
else:
|
305
336
|
_LOGGER.debug('Could not fetch any positional data')
|
337
|
+
return False
|
306
338
|
|
307
339
|
async def get_vehicleHealthWarnings(self):
|
308
340
|
if self._relevantCapabilties.get('vehicleHealthWarnings', {}).get('active', False):
|
309
341
|
data = await self._connection.getVehicleHealthWarnings(self.vin, self._apibase)
|
310
342
|
if data:
|
311
|
-
#warningsList = data.get('warninglights',{}).get('statuses',[])
|
312
|
-
#for i in range(len(warningsList)):
|
313
|
-
# _LOGGER.debug(f'Element {i} in warninglights: {warningsList[i]}')
|
314
|
-
# if isinstance(warningsList[i], dict):
|
315
|
-
# if warningsList[i].get('icon',''):
|
316
|
-
# #Value of icon is very long and can lead to problems
|
317
|
-
# _LOGGER.debug(f'Substituting value of icon by \'DELETED\'')
|
318
|
-
# data['warninglights']['statuses'][i]['icon']='DELETED'
|
319
343
|
self._states.update(data)
|
344
|
+
return True
|
320
345
|
else:
|
321
346
|
_LOGGER.debug('Could not fetch vehicle health warnings')
|
347
|
+
return False
|
322
348
|
|
323
349
|
async def get_statusreport(self):
|
324
350
|
"""Fetch status data if function is enabled."""
|
@@ -327,8 +353,10 @@ class Vehicle:
|
|
327
353
|
if data:
|
328
354
|
self._states.update(data)
|
329
355
|
self._last_get_statusreport = datetime.now(tz=None)
|
356
|
+
return True
|
330
357
|
else:
|
331
358
|
_LOGGER.debug('Could not fetch status report')
|
359
|
+
return False
|
332
360
|
|
333
361
|
async def get_maintenance(self):
|
334
362
|
"""Fetch maintenance data if function is enabled."""
|
@@ -336,8 +364,10 @@ class Vehicle:
|
|
336
364
|
data = await self._connection.getMaintenance(self.vin, self._apibase)
|
337
365
|
if data:
|
338
366
|
self._states.update(data)
|
367
|
+
return True
|
339
368
|
else:
|
340
369
|
_LOGGER.debug('Could not fetch status report')
|
370
|
+
return False
|
341
371
|
|
342
372
|
async def get_charger(self):
|
343
373
|
"""Fetch charger data if function is enabled."""
|
@@ -346,8 +376,10 @@ class Vehicle:
|
|
346
376
|
if data:
|
347
377
|
self._states.update(data)
|
348
378
|
self._last_get_charger = datetime.now(tz=None)
|
379
|
+
return True
|
349
380
|
else:
|
350
381
|
_LOGGER.debug('Could not fetch charger data')
|
382
|
+
return False
|
351
383
|
|
352
384
|
async def get_departure_timers(self):
|
353
385
|
"""Fetch timer data if function is enabled."""
|
@@ -356,8 +388,10 @@ class Vehicle:
|
|
356
388
|
if data:
|
357
389
|
self._states.update(data)
|
358
390
|
self._last_get_departure_timers = datetime.now(tz=None)
|
391
|
+
return True
|
359
392
|
else:
|
360
393
|
_LOGGER.debug('Could not fetch timers')
|
394
|
+
return False
|
361
395
|
|
362
396
|
async def get_departure_profiles(self):
|
363
397
|
"""Fetch timer data if function is enabled."""
|
@@ -366,8 +400,10 @@ class Vehicle:
|
|
366
400
|
if data:
|
367
401
|
self._states.update(data)
|
368
402
|
self._last_get_departure_profiles = datetime.now(tz=None)
|
403
|
+
return True
|
369
404
|
else:
|
370
405
|
_LOGGER.debug('Could not fetch timers')
|
406
|
+
return False
|
371
407
|
|
372
408
|
#async def wait_for_request(self, section, request, retryCount=36):
|
373
409
|
"""Update status of outstanding requests."""
|
@@ -1000,7 +1036,7 @@ class Vehicle:
|
|
1000
1036
|
async def set_climatisation_temp(self, temperature=20):
|
1001
1037
|
"""Set climatisation target temp."""
|
1002
1038
|
if self.is_electric_climatisation_supported or self.is_auxiliary_climatisation_supported:
|
1003
|
-
if 16 <=
|
1039
|
+
if 16 <= float(temperature) <= 30:
|
1004
1040
|
data = {
|
1005
1041
|
'climatisationWithoutExternalPower': self.climatisation_without_external_power,
|
1006
1042
|
'targetTemperature': temperature,
|
@@ -1051,28 +1087,30 @@ class Vehicle:
|
|
1051
1087
|
data = {}
|
1052
1088
|
# Validate user input
|
1053
1089
|
if mode.lower() not in ['electric', 'auxiliary', 'start', 'stop', 'on', 'off']:
|
1090
|
+
_LOGGER.error(f"Invalid mode for 'set_climatisation': {mode}")
|
1054
1091
|
raise SeatInvalidRequestException(f"Invalid mode for set_climatisation: {mode}")
|
1055
1092
|
elif mode == 'auxiliary' and spin is None:
|
1056
1093
|
raise SeatInvalidRequestException("Starting auxiliary heater requires provided S-PIN")
|
1057
1094
|
if temp is not None:
|
1058
|
-
if not isinstance(temp, float):
|
1095
|
+
if not isinstance(temp, float) and not isinstance(temp, int):
|
1096
|
+
_LOGGER.error(f"Invalid type for temp. type={type(temp)}")
|
1059
1097
|
raise SeatInvalidRequestException(f"Invalid type for temp")
|
1060
1098
|
elif not 16 <= float(temp) <=30:
|
1061
1099
|
raise SeatInvalidRequestException(f"Invalid value for temp")
|
1062
1100
|
else:
|
1063
1101
|
temp = self.climatisation_target_temperature
|
1064
|
-
if hvpower is not None:
|
1065
|
-
|
1066
|
-
|
1102
|
+
#if hvpower is not None:
|
1103
|
+
# if not isinstance(hvpower, bool):
|
1104
|
+
# raise SeatInvalidRequestException(f"Invalid type for hvpower")
|
1067
1105
|
if self.is_electric_climatisation_supported:
|
1068
1106
|
if self._relevantCapabilties.get('climatisation', {}).get('active', False):
|
1069
1107
|
if mode in ['Start', 'start', 'Electric', 'electric', 'On', 'on']:
|
1070
1108
|
mode = 'start'
|
1071
1109
|
if mode in ['start', 'auxiliary']:
|
1072
|
-
if hvpower is not None:
|
1073
|
-
|
1074
|
-
else:
|
1075
|
-
|
1110
|
+
#if hvpower is not None:
|
1111
|
+
# withoutHVPower = hvpower
|
1112
|
+
#else:
|
1113
|
+
# withoutHVPower = self.climatisation_without_external_power
|
1076
1114
|
data = {
|
1077
1115
|
'targetTemperature': temp,
|
1078
1116
|
'targetTemperatureUnit': 'celsius',
|
@@ -1159,7 +1197,7 @@ class Vehicle:
|
|
1159
1197
|
self._requests['climatisation'] = {'status': 'Exception'}
|
1160
1198
|
raise SeatException('Climatisation action failed')
|
1161
1199
|
|
1162
|
-
|
1200
|
+
# Parking heater heating/ventilation (RS)
|
1163
1201
|
async def set_pheater(self, mode, spin):
|
1164
1202
|
"""Set the mode for the parking heater."""
|
1165
1203
|
if not self.is_pheater_heating_supported:
|
@@ -1202,7 +1240,7 @@ class Vehicle:
|
|
1202
1240
|
self._requests['preheater'] = {'status': 'Exception'}
|
1203
1241
|
raise SeatException('Pre-heater action failed')
|
1204
1242
|
|
1205
|
-
|
1243
|
+
# Lock
|
1206
1244
|
async def set_lock(self, action, spin):
|
1207
1245
|
"""Remote lock and unlock actions."""
|
1208
1246
|
#if not self._services.get('rlu_v1', False):
|
@@ -1264,7 +1302,7 @@ class Vehicle:
|
|
1264
1302
|
self._requests['lock'] = {'status': 'Exception'}
|
1265
1303
|
raise SeatException('Lock action failed')
|
1266
1304
|
|
1267
|
-
|
1305
|
+
# Honk and flash (RHF)
|
1268
1306
|
async def set_honkandflash(self, action, lat=None, lng=None):
|
1269
1307
|
"""Turn on/off honk and flash."""
|
1270
1308
|
if not self._relevantCapabilties.get('honkAndFlash', {}).get('active', False):
|
@@ -1321,7 +1359,7 @@ class Vehicle:
|
|
1321
1359
|
self._requests['honkandflash'] = {'status': 'Exception'}
|
1322
1360
|
raise SeatException('Honk and flash action failed')
|
1323
1361
|
|
1324
|
-
|
1362
|
+
# Refresh vehicle data (VSR)
|
1325
1363
|
async def set_refresh(self):
|
1326
1364
|
"""Wake up vehicle and update status data."""
|
1327
1365
|
if not self._relevantCapabilties.get('state', {}).get('active', False):
|
@@ -1348,6 +1386,11 @@ class Vehicle:
|
|
1348
1386
|
'status': response.get('status', 'Unknown'),
|
1349
1387
|
'id': response.get('id', 0)
|
1350
1388
|
}
|
1389
|
+
# if firebaseStatus is FIREBASE_STATUS_ACTIVATED, the request is assumed successful. Waiting for push notification before rereading status
|
1390
|
+
if self.firebaseStatus == FIREBASE_STATUS_ACTIVATED:
|
1391
|
+
_LOGGER.debug('POST request for wakeup vehicle assumed successful. Waiting for push notification')
|
1392
|
+
return True
|
1393
|
+
await self.update(updateType=1) #full update after set_refresh
|
1351
1394
|
return True
|
1352
1395
|
except(SeatInvalidRequestException, SeatException):
|
1353
1396
|
raise
|
@@ -1357,7 +1400,7 @@ class Vehicle:
|
|
1357
1400
|
raise SeatException('Data refresh failed')
|
1358
1401
|
|
1359
1402
|
#### Vehicle class helpers ####
|
1360
|
-
|
1403
|
+
# Vehicle info
|
1361
1404
|
@property
|
1362
1405
|
def attrs(self):
|
1363
1406
|
return self._states
|
@@ -1390,7 +1433,7 @@ class Vehicle:
|
|
1390
1433
|
|
1391
1434
|
|
1392
1435
|
#### Information from vehicle states ####
|
1393
|
-
|
1436
|
+
# Car information
|
1394
1437
|
@property
|
1395
1438
|
def nickname(self):
|
1396
1439
|
return self._properties.get('vehicleNickname', '')
|
@@ -1479,7 +1522,7 @@ class Vehicle:
|
|
1479
1522
|
if self._modelimages is not None:
|
1480
1523
|
return True
|
1481
1524
|
|
1482
|
-
|
1525
|
+
# Lights
|
1483
1526
|
@property
|
1484
1527
|
def parking_light(self):
|
1485
1528
|
"""Return true if parking light is on"""
|
@@ -1498,7 +1541,7 @@ class Vehicle:
|
|
1498
1541
|
else:
|
1499
1542
|
return False
|
1500
1543
|
|
1501
|
-
|
1544
|
+
# Connection status
|
1502
1545
|
@property
|
1503
1546
|
def last_connected(self):
|
1504
1547
|
"""Return when vehicle was last connected to connect servers."""
|
@@ -1515,7 +1558,7 @@ class Vehicle:
|
|
1515
1558
|
if 'updatedAt' in self.attrs.get('status', {}):
|
1516
1559
|
return True
|
1517
1560
|
|
1518
|
-
|
1561
|
+
# Update status
|
1519
1562
|
@property
|
1520
1563
|
def last_full_update(self):
|
1521
1564
|
"""Return when the last full update for the vehicle took place."""
|
@@ -1527,7 +1570,7 @@ class Vehicle:
|
|
1527
1570
|
if hasattr(self,'_last_full_update'):
|
1528
1571
|
return True
|
1529
1572
|
|
1530
|
-
|
1573
|
+
# Service information
|
1531
1574
|
@property
|
1532
1575
|
def distance(self):
|
1533
1576
|
"""Return vehicle odometer."""
|
@@ -1615,7 +1658,7 @@ class Vehicle:
|
|
1615
1658
|
return True
|
1616
1659
|
return False
|
1617
1660
|
|
1618
|
-
|
1661
|
+
# Charger related states for EV and PHEV
|
1619
1662
|
@property
|
1620
1663
|
def charging(self):
|
1621
1664
|
"""Return battery level"""
|
@@ -1874,7 +1917,7 @@ class Vehicle:
|
|
1874
1917
|
if self.attrs.get('charging', {}).get('info', {}).get('settings', {}).get('targetSoc', False):
|
1875
1918
|
return True
|
1876
1919
|
|
1877
|
-
|
1920
|
+
# Vehicle location states
|
1878
1921
|
@property
|
1879
1922
|
def position(self):
|
1880
1923
|
"""Return position."""
|
@@ -1941,7 +1984,7 @@ class Vehicle:
|
|
1941
1984
|
if 'parkingTimeUTC' in self.attrs.get('findCarResponse', {}):
|
1942
1985
|
return True
|
1943
1986
|
|
1944
|
-
|
1987
|
+
# Vehicle fuel level and range
|
1945
1988
|
@property
|
1946
1989
|
def primary_range(self):
|
1947
1990
|
value = -1
|
@@ -2080,7 +2123,7 @@ class Vehicle:
|
|
2080
2123
|
return self.is_secondary_range_supported
|
2081
2124
|
return False
|
2082
2125
|
|
2083
|
-
|
2126
|
+
# Climatisation settings
|
2084
2127
|
@property
|
2085
2128
|
def climatisation_target_temperature(self):
|
2086
2129
|
"""Return the target temperature from climater."""
|
@@ -2154,7 +2197,7 @@ class Vehicle:
|
|
2154
2197
|
else:
|
2155
2198
|
return False
|
2156
2199
|
|
2157
|
-
|
2200
|
+
# Climatisation, electric
|
2158
2201
|
@property
|
2159
2202
|
def electric_climatisation_attributes(self):
|
2160
2203
|
"""Return climatisation attributes."""
|
@@ -2262,7 +2305,7 @@ class Vehicle:
|
|
2262
2305
|
return True
|
2263
2306
|
return False
|
2264
2307
|
|
2265
|
-
|
2308
|
+
# Parking heater, "legacy" auxiliary climatisation
|
2266
2309
|
@property
|
2267
2310
|
def pheater_duration(self):
|
2268
2311
|
return self._climate_duration
|
@@ -2310,7 +2353,7 @@ class Vehicle:
|
|
2310
2353
|
if self.attrs.get('heating', {}).get('climatisationStateReport', {}).get('climatisationState', False):
|
2311
2354
|
return True
|
2312
2355
|
|
2313
|
-
|
2356
|
+
# Windows
|
2314
2357
|
@property
|
2315
2358
|
def windows_closed(self):
|
2316
2359
|
return (self.window_closed_left_front and self.window_closed_left_back and self.window_closed_right_front and self.window_closed_right_back)
|
@@ -2417,7 +2460,7 @@ class Vehicle:
|
|
2417
2460
|
# response = self.attrs.get('status')['windows'].get('sunRoof', '')
|
2418
2461
|
return True if response != '' else False
|
2419
2462
|
|
2420
|
-
|
2463
|
+
# Locks
|
2421
2464
|
@property
|
2422
2465
|
def door_locked(self):
|
2423
2466
|
# LEFT FRONT
|
@@ -2460,7 +2503,7 @@ class Vehicle:
|
|
2460
2503
|
return True
|
2461
2504
|
return False
|
2462
2505
|
|
2463
|
-
|
2506
|
+
# Doors, hood and trunk
|
2464
2507
|
@property
|
2465
2508
|
def hood_closed(self):
|
2466
2509
|
"""Return true if hood is closed"""
|
@@ -2545,7 +2588,7 @@ class Vehicle:
|
|
2545
2588
|
response = self.attrs.get('status')['trunk'].get('open', 0)
|
2546
2589
|
return True if response != 0 else False
|
2547
2590
|
|
2548
|
-
|
2591
|
+
# Departure timers
|
2549
2592
|
@property
|
2550
2593
|
def departure1(self):
|
2551
2594
|
"""Return timer status and attributes."""
|
@@ -2657,7 +2700,7 @@ class Vehicle:
|
|
2657
2700
|
return True
|
2658
2701
|
return False
|
2659
2702
|
|
2660
|
-
|
2703
|
+
# Departure profiles
|
2661
2704
|
@property
|
2662
2705
|
def departure_profile1(self):
|
2663
2706
|
"""Return profile status and attributes."""
|
@@ -2730,7 +2773,7 @@ class Vehicle:
|
|
2730
2773
|
return True
|
2731
2774
|
return False
|
2732
2775
|
|
2733
|
-
|
2776
|
+
# Trip data
|
2734
2777
|
@property
|
2735
2778
|
def trip_last_entry(self):
|
2736
2779
|
return self.attrs.get('tripstatistics', {}).get('short', [{},{}])[-1]
|
@@ -2955,7 +2998,26 @@ class Vehicle:
|
|
2955
2998
|
if response and type(response.get('totalElectricConsumption', None)) in (float, int):
|
2956
2999
|
return True
|
2957
3000
|
|
2958
|
-
#
|
3001
|
+
# Area alarm
|
3002
|
+
@property
|
3003
|
+
def area_alarm(self):
|
3004
|
+
"""Return True, if attribute areaAlarm is not {}"""
|
3005
|
+
alarmPresent = self.attrs.get('areaAlarm', {})
|
3006
|
+
if alarmPresent !={}:
|
3007
|
+
# Delete an area alarm if it is older than 900 seconds
|
3008
|
+
alarmTimestamp = self.attrs.get('areaAlarm', {}).get('timestamp', 0)
|
3009
|
+
if alarmTimestamp < datetime.now(tz=None) - timedelta(seconds= 900):
|
3010
|
+
self.attrs.pop("areaAlarm")
|
3011
|
+
alarmPresent = {}
|
3012
|
+
return False if alarmPresent == {} else True
|
3013
|
+
|
3014
|
+
@property
|
3015
|
+
def is_area_alarm_supported(self):
|
3016
|
+
"""Return True, if vehicle supports area alarm (always True at the moment)"""
|
3017
|
+
# Always True at the moment. Have to check, if the geofence capability is a necessary condition
|
3018
|
+
return True
|
3019
|
+
|
3020
|
+
# Status of set data requests
|
2959
3021
|
@property
|
2960
3022
|
def refresh_action_status(self):
|
2961
3023
|
"""Return latest status of data refresh request."""
|
@@ -3060,7 +3122,7 @@ class Vehicle:
|
|
3060
3122
|
"""Data update is supported."""
|
3061
3123
|
return True
|
3062
3124
|
|
3063
|
-
|
3125
|
+
# Honk and flash
|
3064
3126
|
@property
|
3065
3127
|
def request_honkandflash(self):
|
3066
3128
|
"""State is always False"""
|
@@ -3083,7 +3145,7 @@ class Vehicle:
|
|
3083
3145
|
if self._relevantCapabilties.get('honkAndFlash', {}).get('active', False):
|
3084
3146
|
return True
|
3085
3147
|
|
3086
|
-
|
3148
|
+
# Requests data
|
3087
3149
|
@property
|
3088
3150
|
def request_in_progress(self):
|
3089
3151
|
"""Request in progress is always supported."""
|
@@ -3138,7 +3200,7 @@ class Vehicle:
|
|
3138
3200
|
#if self.is_request_in_progress_supported:
|
3139
3201
|
# return True if self._requests.get('remaining', False) else False
|
3140
3202
|
|
3141
|
-
|
3203
|
+
#### Helper functions ####
|
3142
3204
|
def __str__(self):
|
3143
3205
|
return self.vin
|
3144
3206
|
|
@@ -3157,7 +3219,7 @@ class Vehicle:
|
|
3157
3219
|
|
3158
3220
|
async def stopFirebase(self):
|
3159
3221
|
# Check if firebase is activated
|
3160
|
-
if self.firebaseStatus
|
3222
|
+
if self.firebaseStatus not in (FIREBASE_STATUS_ACTIVATED, FIREBASE_STATUS_ACTIVATION_STOPPED):
|
3161
3223
|
_LOGGER.info(f'No need to stop firebase. Firebase status={self.firebaseStatus}')
|
3162
3224
|
return self.firebaseStatus
|
3163
3225
|
|
@@ -3171,7 +3233,7 @@ class Vehicle:
|
|
3171
3233
|
_LOGGER.warning('Stopping of firebase messaging failed.')
|
3172
3234
|
return self.firebaseStatus
|
3173
3235
|
|
3174
|
-
#await asyncio.sleep(5)
|
3236
|
+
#await asyncio.sleep(5)
|
3175
3237
|
self.firebaseStatus = FIREBASE_STATUS_NOT_INITIALISED
|
3176
3238
|
_LOGGER.info('Stopping of firebase messaging was successful.')
|
3177
3239
|
return self.firebaseStatus
|
@@ -3236,17 +3298,21 @@ class Vehicle:
|
|
3236
3298
|
_LOGGER.debug(f'Received push notification: notification id={notification}, type={obj.get('data',{}).get('type','')}, requestId={obj.get('data',{}).get('requestId','[None]')}')
|
3237
3299
|
_LOGGER.debug(f' data_message={data_message}, payload={obj.get('data',{}).get('payload','[None]')}')
|
3238
3300
|
|
3239
|
-
#temporary output of notifications in a file
|
3240
|
-
if self.updateCallback == self.update:
|
3241
|
-
self.storeFirebaseNotifications(obj, notification, data_message)
|
3242
|
-
|
3243
3301
|
if self.firebaseStatus != FIREBASE_STATUS_ACTIVATED:
|
3244
|
-
|
3245
|
-
|
3246
|
-
|
3302
|
+
if self.firebaseStatus != FIREBASE_STATUS_ACTIVATION_STOPPED:
|
3303
|
+
_LOGGER.info(f'While firebase is not fully activated, received notifications are just acknowledged.')
|
3304
|
+
# As long as the firebase status is not set to activated, ignore the notifications
|
3305
|
+
return False
|
3306
|
+
else:
|
3307
|
+
# It seems that the firebase connection still works although fcmpushclient.is_started() returned False some time ago
|
3308
|
+
_LOGGER.info(f'Firebase status={self.firebaseStatus}, but PyCupra still receives push notifications.')
|
3309
|
+
self.firebaseStatus = FIREBASE_STATUS_ACTIVATED
|
3310
|
+
_LOGGER.info(f'Set firebase status back to {self.firebaseStatus}.')
|
3311
|
+
|
3247
3312
|
|
3248
3313
|
type = obj.get('data',{}).get('type','')
|
3249
3314
|
requestId = obj.get('data',{}).get('requestId','')
|
3315
|
+
payload = obj.get('data',{}).get('payload','')
|
3250
3316
|
openRequest = -1
|
3251
3317
|
if requestId != '':
|
3252
3318
|
_LOGGER.info(f'Received notification of type \'{type}\', request id={requestId} ')
|
@@ -3317,7 +3383,29 @@ class Vehicle:
|
|
3317
3383
|
await self.updateCallback(2)
|
3318
3384
|
else:
|
3319
3385
|
_LOGGER.debug(f'It is now {datetime.now(tz=None)}. Last get_climater was at {self._last_get_climater}. So no need to update.')
|
3320
|
-
elif type
|
3386
|
+
elif type in ('vehicle-area-alarm-vehicle-exits-zone-triggered', 'vehicle-area-alarm-vehicle-enters-zone-triggered'):
|
3387
|
+
#if self._last_get_position < datetime.now(tz=None) - timedelta(seconds= 30):
|
3388
|
+
# # Update position data only if the last one is older than timedelta
|
3389
|
+
# await self.get_position()
|
3390
|
+
#else:
|
3391
|
+
# _LOGGER.debug(f'It is now {datetime.now(tz=None)}. Last get_position was at {self._last_get_position}. So no need to update.')
|
3392
|
+
if payload != '':
|
3393
|
+
payloadDict = json.loads(payload) # Convert json string to dict
|
3394
|
+
#_LOGGER.debug(f'payloadDict is dict: {isinstance(payloadDict, dict)}')
|
3395
|
+
zones = payloadDict.get('description',{}).get('values',[])
|
3396
|
+
else:
|
3397
|
+
_LOGGER.warning(f'Missing information about areas. Payload ={payload}')
|
3398
|
+
zones = []
|
3399
|
+
areaAlarm = {'areaAlarm' : {
|
3400
|
+
'type': 'vehicle-exits-zone' if type=='vehicle-area-alarm-vehicle-exits-zone-triggered' else 'vehicle-enters-zone',
|
3401
|
+
'timestamp': datetime.now(tz=None),
|
3402
|
+
'zones': zones
|
3403
|
+
}
|
3404
|
+
}
|
3405
|
+
self._states.update(areaAlarm)
|
3406
|
+
if self.updateCallback:
|
3407
|
+
await self.updateCallback(2)
|
3408
|
+
elif type in ('vehicle-wake-up-succeeded', 'vehicle-wakeup-succeeded'):
|
3321
3409
|
if self._requests.get('refresh', {}).get('id', None):
|
3322
3410
|
openRequest= self._requests.get('refresh', {}).get('id', None)
|
3323
3411
|
if openRequest == requestId:
|
@@ -3327,20 +3415,8 @@ class Vehicle:
|
|
3327
3415
|
# Do full update only if the last one is older than timedelta or if the notification belongs to an open request initiated by PyCupra
|
3328
3416
|
if self.updateCallback:
|
3329
3417
|
await self.updateCallback(1)
|
3418
|
+
elif type in ('vehicle-area-alert-added', 'vehicle-area-alert-updated'):
|
3419
|
+
_LOGGER.info(f' Intentionally ignoring a notification of type \'{type}\')')
|
3330
3420
|
else:
|
3331
3421
|
_LOGGER.warning(f' Don\'t know what to do with a notification of type \'{type}\')')
|
3332
3422
|
|
3333
|
-
|
3334
|
-
def storeFirebaseNotifications(self, obj, notification, data_message):
|
3335
|
-
_LOGGER.debug(f'In storeFirebaseNotifications. notification={notification}')
|
3336
|
-
fName = self._firebaseCredentialsFileName
|
3337
|
-
fName = fName.replace('pycupra_firebase_credentials.json', 'pycupra_firebasenotifications.txt')
|
3338
|
-
|
3339
|
-
with open(fName, "a") as ofile:
|
3340
|
-
ofile.write(f'{datetime.now()}\n')
|
3341
|
-
ofile.write(f' notification id={notification}, data_message={data_message}\n')
|
3342
|
-
ofile.write(f' obj={obj}\n')
|
3343
|
-
ofile.write("----------------------------------------------------------------\n")
|
3344
|
-
|
3345
|
-
|
3346
|
-
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pycupra
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.9
|
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,25 +1,25 @@
|
|
1
1
|
pycupra/__init__.py,sha256=p0880jPkLqOErX3u3qaLboBLOsEHFpe44axApdaGeqI,231
|
2
|
-
pycupra/__version__.py,sha256=
|
3
|
-
pycupra/connection.py,sha256=
|
4
|
-
pycupra/const.py,sha256=
|
5
|
-
pycupra/dashboard.py,sha256=
|
2
|
+
pycupra/__version__.py,sha256=dcxJ-u8Zz6qTGBXri5kGr0y8fa_8l43365hGXeOK-zU,207
|
3
|
+
pycupra/connection.py,sha256=Knu3vzokMRrsg9psjeD_r-2cl04ySJ1j7Mrn2g9mzdg,92941
|
4
|
+
pycupra/const.py,sha256=5b4uuNUE1AGZHmqQfIZv-76Ad20mJTXXQPGI8TU6FfY,10631
|
5
|
+
pycupra/dashboard.py,sha256=AlffEx8WmhLaSwX-eVcrOc54rUmwpzZUuR1fhruYkzI,45337
|
6
6
|
pycupra/exceptions.py,sha256=Nq_F79GP8wjHf5lpvPy9TbSIrRHAJrFMo0T1N9TcgSQ,2917
|
7
|
-
pycupra/firebase.py,sha256=
|
7
|
+
pycupra/firebase.py,sha256=lmI4a8f5VAlmHAqP2OiJWZhn7dmhyHkIBxL252qdtkA,3454
|
8
8
|
pycupra/utilities.py,sha256=6sDxWP13-XtxmqhuBJBGdVbkj48BQ9AxFMrBPxH0J7g,2679
|
9
|
-
pycupra/vehicle.py,sha256=
|
9
|
+
pycupra/vehicle.py,sha256=12pFVqgIRkPMJ9IoBt0TAuSS4RRQOdTCq4-ltNtbN9c,162376
|
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
|
13
13
|
pycupra/firebase_messaging/checkin_pb2.py,sha256=lFzCIAkYz9NFUpRbVuW-2kM_EaYKVWHeifHS1PV2eHQ,2795
|
14
14
|
pycupra/firebase_messaging/checkin_pb2.pyi,sha256=mHOqbedt5jZDI20jcyFrTMSnQ0f_tq4zkIlHiaSC3xI,14626
|
15
15
|
pycupra/firebase_messaging/const.py,sha256=XMy8kJ37uBSkTpVpdLeSjxk5UIPuvDuo-rxYdgmo2G8,1191
|
16
|
-
pycupra/firebase_messaging/fcmpushclient.py,sha256=
|
16
|
+
pycupra/firebase_messaging/fcmpushclient.py,sha256=5kAp6rnl9EJqVPn9OfHFKUfFDRWA9LAVbfiL-pLRSqo,30550
|
17
17
|
pycupra/firebase_messaging/fcmregister.py,sha256=yZngC-0ZfTygtjfdzg03OW_3xk2n_uSQQ3Lrash5Y_E,18091
|
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.
|
22
|
-
pycupra-0.1.
|
23
|
-
pycupra-0.1.
|
24
|
-
pycupra-0.1.
|
25
|
-
pycupra-0.1.
|
21
|
+
pycupra-0.1.9.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
|
22
|
+
pycupra-0.1.9.dist-info/METADATA,sha256=5LDPYAqO74WlAZanWVES__uzRngZlq2t_JS8cbABI9w,3757
|
23
|
+
pycupra-0.1.9.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
24
|
+
pycupra-0.1.9.dist-info/top_level.txt,sha256=9Lbj_jG4JvpGwt6K3AwhWFc0XieDnuHFOP4x44wSXSQ,8
|
25
|
+
pycupra-0.1.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|