carconnectivity-connector-seatcupra 0.1a14__py3-none-any.whl → 0.1a16__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-seatcupra
3
- Version: 0.1a14
3
+ Version: 0.1a16
4
4
  Summary: CarConnectivity connector for Seat and Cupra services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -37,7 +37,7 @@ Classifier: Topic :: Software Development :: Libraries
37
37
  Requires-Python: >=3.9
38
38
  Description-Content-Type: text/markdown
39
39
  License-File: LICENSE
40
- Requires-Dist: carconnectivity>=0.4a6
40
+ Requires-Dist: carconnectivity>=0.4a10
41
41
  Requires-Dist: oauthlib~=3.2.2
42
42
  Requires-Dist: requests~=2.32.3
43
43
  Requires-Dist: jwt~=1.3.1
@@ -1,10 +1,10 @@
1
1
  carconnectivity_connectors/seatcupra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- carconnectivity_connectors/seatcupra/_version.py,sha256=uxem9Z0JbrrSqB5GMvuMAyGSfBZfrJvSAu8udDrjXQg,509
2
+ carconnectivity_connectors/seatcupra/_version.py,sha256=Q2vMRbSVvIsvGRGZpDL_EO13NrfM1hiyRO4RK2N2B04,509
3
3
  carconnectivity_connectors/seatcupra/capability.py,sha256=Oe9tC_u69bj6VmOuNJ21RKoETe2j3QyZCoz-VgcZPQ0,4523
4
4
  carconnectivity_connectors/seatcupra/charging.py,sha256=BJe_5GEB0JkP78tpU6kyKpwuwjDZHvm-kt3PTlpQHeU,3336
5
5
  carconnectivity_connectors/seatcupra/climatization.py,sha256=0xxWlxrheAPzkVT8WRQtbm6ExZmVdgW7lUdOXyS_qWY,1695
6
- carconnectivity_connectors/seatcupra/command_impl.py,sha256=mtw8ZwJLmf79fPDZ1N3ImLfB8Gt9JPbzjMuIo2y5v3M,2879
7
- carconnectivity_connectors/seatcupra/connector.py,sha256=edw4PSE8HqxSeG6_eOSKl55hNF1aZt-_pnOiVxzQBl0,100885
6
+ carconnectivity_connectors/seatcupra/command_impl.py,sha256=LmBOCWGZPfJCG_4-5449xvO6NAvnPDsAWEBKlsG4WoI,3051
7
+ carconnectivity_connectors/seatcupra/connector.py,sha256=BeiW5YQtmNckm-CsYU_fd2KT2LmdOzB6druVG-QNUNE,101715
8
8
  carconnectivity_connectors/seatcupra/vehicle.py,sha256=s0G-HqG5qcwStDxD3649KgLMa3lKPZ4TOGWRJEuQzsQ,3403
9
9
  carconnectivity_connectors/seatcupra/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  carconnectivity_connectors/seatcupra/auth/auth_util.py,sha256=Y81h8fGOMSMgPtE4wI_TI9WgE_s43uaPjRLBBINhj4g,4433
@@ -14,8 +14,8 @@ carconnectivity_connectors/seatcupra/auth/session_manager.py,sha256=ZIDvC848T3fy
14
14
  carconnectivity_connectors/seatcupra/auth/vw_web_session.py,sha256=CcI6m68IyRs6WsMDu-IsW3Dj85vyGiMmxvFqNETMHO0,10929
15
15
  carconnectivity_connectors/seatcupra/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
16
16
  carconnectivity_connectors/seatcupra/ui/connector_ui.py,sha256=SNYnlcGJpbWhuLiIHD2l6H9IfSiMz3IgmvXsdossDnE,1412
17
- carconnectivity_connector_seatcupra-0.1a14.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
18
- carconnectivity_connector_seatcupra-0.1a14.dist-info/METADATA,sha256=Sn7852ULtuZqRoHEFQjCgjmDXxAptyYZcq6I2mhkg8M,5641
19
- carconnectivity_connector_seatcupra-0.1a14.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
20
- carconnectivity_connector_seatcupra-0.1a14.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
21
- carconnectivity_connector_seatcupra-0.1a14.dist-info/RECORD,,
17
+ carconnectivity_connector_seatcupra-0.1a16.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
18
+ carconnectivity_connector_seatcupra-0.1a16.dist-info/METADATA,sha256=HCIYpy1TCxYmcQGaceTHYYog1OtZqs4a71o-Gr-fpjA,5642
19
+ carconnectivity_connector_seatcupra-0.1a16.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
20
+ carconnectivity_connector_seatcupra-0.1a16.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
21
+ carconnectivity_connector_seatcupra-0.1a16.dist-info/RECORD,,
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.1a14'
20
+ __version__ = version = '0.1a16'
21
21
  __version_tuple__ = version_tuple = (0, 1)
@@ -31,6 +31,8 @@ class SpinCommand(GenericCommand):
31
31
 
32
32
  @value.setter
33
33
  def value(self, new_value: Optional[Union[str, Dict]]) -> None:
34
+ # Execute early hooks before parsing the value
35
+ new_value = self._execute_on_set_hook(new_value, early_hook=True)
34
36
  if isinstance(new_value, str):
35
37
  parser = ThrowingArgumentParser(prog='', add_help=False, exit_on_error=False)
36
38
  parser.add_argument('command', help='Command to execute', type=SpinCommand.Command,
@@ -55,8 +57,8 @@ class SpinCommand(GenericCommand):
55
57
  raise ValueError('Invalid value for SpinCommand. '
56
58
  f'Command must be one of {SpinCommand.Command}')
57
59
  if self._is_changeable:
58
- for hook in self._on_set_hooks:
59
- new_value = hook(self, new_value)
60
+ # Execute late hooks before setting the value
61
+ new_value = self._execute_on_set_hook(new_value, early_hook=False)
60
62
  self._set_value(new_value)
61
63
  else:
62
64
  raise TypeError('You cannot set this attribute. Attribute is not mutable.')
@@ -6,6 +6,7 @@ import threading
6
6
 
7
7
  import json
8
8
  import os
9
+ import traceback
9
10
  import logging
10
11
  import netrc
11
12
  from datetime import datetime, timezone, timedelta
@@ -77,15 +78,10 @@ class Connector(BaseConnector):
77
78
 
78
79
  self.connected: BooleanAttribute = BooleanAttribute(name="connected", parent=self, tags={'connector_custom'})
79
80
  self.interval: DurationAttribute = DurationAttribute(name="interval", parent=self, tags={'connector_custom'})
80
-
81
- def __check_interval(attribute: GenericAttribute, value: Any) -> Any:
82
- del attribute
83
- if value is not None and value < timedelta(seconds=180):
84
- raise ValueError('Intervall must be at least 180 seconds')
85
- return value
86
-
81
+ self.interval.minimum = timedelta(seconds=180)
87
82
  self.interval._is_changeable = True # pylint: disable=protected-access
88
- self.interval._add_on_set_hook(__check_interval) # pylint: disable=protected-access
83
+
84
+ self._healthy = False
89
85
 
90
86
  self.commands: Commands = Commands(parent=self)
91
87
 
@@ -171,6 +167,7 @@ class Connector(BaseConnector):
171
167
  self._background_thread = threading.Thread(target=self._background_loop, daemon=False)
172
168
  self._background_thread.name = 'carconnectivity.connectors.seatcupra-background'
173
169
  self._background_thread.start()
170
+ self._healthy = True
174
171
 
175
172
  def _background_loop(self) -> None:
176
173
  self._stop_event.clear()
@@ -206,6 +203,10 @@ class Connector(BaseConnector):
206
203
  except TemporaryAuthenticationError as err:
207
204
  LOG.error('Temporary authentification error during update (%s). Will try again after configured interval of %ss', str(err), interval)
208
205
  self._stop_event.wait(interval)
206
+ except Exception as err:
207
+ LOG.critical('Critical error during update: %s', traceback.format_exc())
208
+ self._healthy = False
209
+ raise err
209
210
  else:
210
211
  self._stop_event.wait(interval)
211
212
 
@@ -285,6 +286,7 @@ class Connector(BaseConnector):
285
286
  vehicle_to_update = self.fetch_parking_position(vehicle_to_update)
286
287
  if vehicle_to_update.capabilities.has_capability('vehicleHealthInspection'):
287
288
  vehicle_to_update = self.fetch_maintenance(vehicle_to_update)
289
+ self.car_connectivity.transaction_end()
288
290
 
289
291
  def fetch_vehicles(self) -> None:
290
292
  """
@@ -861,6 +863,9 @@ class Connector(BaseConnector):
861
863
  vehicle.climatization.settings.target_temperature._set_value(value=target_temperature, # pylint: disable=protected-access
862
864
  measured=captured_at,
863
865
  unit=Temperature.C)
866
+ vehicle.climatization.settings.target_temperature.precision = 0.5
867
+ vehicle.climatization.settings.target_temperature.minimum = 16.0
868
+ vehicle.climatization.settings.target_temperature.maximum = 29.5
864
869
  elif 'targetTemperatureInFahrenheit' in data and data['targetTemperatureInFahrenheit'] is not None:
865
870
  # pylint: disable-next=protected-access
866
871
  vehicle.climatization.settings.target_temperature._add_on_set_hook(self.__on_air_conditioning_settings_change)
@@ -870,6 +875,9 @@ class Connector(BaseConnector):
870
875
  vehicle.climatization.settings.target_temperature._set_value(value=target_temperature, # pylint: disable=protected-access
871
876
  measured=captured_at,
872
877
  unit=Temperature.F)
878
+ vehicle.climatization.settings.target_temperature.precision = 0.5
879
+ vehicle.climatization.settings.target_temperature.minimum = 61.0
880
+ vehicle.climatization.settings.target_temperature.maximum = 85.5
873
881
  else:
874
882
  vehicle.climatization.settings.target_temperature._set_value(None) # pylint: disable=protected-access
875
883
  if 'climatisationWithoutExternalPower' in data and data['climatisationWithoutExternalPower'] is not None:
@@ -1162,12 +1170,15 @@ class Connector(BaseConnector):
1162
1170
  url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/vehicles/{vin}/climatisation/start'
1163
1171
  if vehicle.climatization.settings is None:
1164
1172
  raise CommandError('Could not control climatisation, there are no climatisation settings for the vehicle available.')
1173
+ precision: float = 0.5
1165
1174
  if 'target_temperature' in command_arguments:
1166
1175
  # Round target temperature to nearest 0.5
1167
- command_dict['targetTemperature'] = round(command_arguments['target_temperature'] * 2) / 2
1176
+ command_dict['targetTemperature'] = round(command_arguments['target_temperature'] / precision) * precision
1168
1177
  elif vehicle.climatization.settings.target_temperature is not None and vehicle.climatization.settings.target_temperature.enabled \
1169
1178
  and vehicle.climatization.settings.target_temperature.value is not None:
1170
1179
  temperature_value = vehicle.climatization.settings.target_temperature.value
1180
+ if vehicle.climatization.settings.target_temperature.precision is not None:
1181
+ precision = vehicle.climatization.settings.target_temperature.precision
1171
1182
  if vehicle.climatization.settings.target_temperature.unit == Temperature.C:
1172
1183
  command_dict['targetTemperatureUnit'] = 'celsius'
1173
1184
  elif vehicle.climatization.settings.target_temperature.unit == Temperature.F:
@@ -1175,7 +1186,7 @@ class Connector(BaseConnector):
1175
1186
  else:
1176
1187
  command_dict['targetTemperatureUnit'] = 'celsius'
1177
1188
  if temperature_value is not None:
1178
- command_dict['targetTemperature'] = round(temperature_value * 2) / 2
1189
+ command_dict['targetTemperature'] = round(temperature_value / precision) * precision
1179
1190
  if 'target_temperature_unit' in command_arguments:
1180
1191
  if command_arguments['target_temperature_unit'] == Temperature.C:
1181
1192
  command_dict['targetTemperatureUnit'] = 'celsius'
@@ -1442,3 +1453,6 @@ class Connector(BaseConnector):
1442
1453
 
1443
1454
  def get_type(self) -> str:
1444
1455
  return "carconnectivity-connector-seatcupra"
1456
+
1457
+ def is_healthy(self) -> bool:
1458
+ return self._healthy and super().is_healthy()