carconnectivity-connector-seatcupra 0.1.2a1__py3-none-any.whl → 0.2__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.
- {carconnectivity_connector_seatcupra-0.1.2a1.dist-info → carconnectivity_connector_seatcupra-0.2.dist-info}/METADATA +4 -3
- {carconnectivity_connector_seatcupra-0.1.2a1.dist-info → carconnectivity_connector_seatcupra-0.2.dist-info}/RECORD +10 -10
- {carconnectivity_connector_seatcupra-0.1.2a1.dist-info → carconnectivity_connector_seatcupra-0.2.dist-info}/WHEEL +1 -1
- carconnectivity_connectors/seatcupra/_version.py +2 -2
- carconnectivity_connectors/seatcupra/auth/my_cupra_session.py +15 -6
- carconnectivity_connectors/seatcupra/charging.py +16 -1
- carconnectivity_connectors/seatcupra/connector.py +293 -29
- carconnectivity_connectors/seatcupra/vehicle.py +12 -4
- {carconnectivity_connector_seatcupra-0.1.2a1.dist-info → carconnectivity_connector_seatcupra-0.2.dist-info/licenses}/LICENSE +0 -0
- {carconnectivity_connector_seatcupra-0.1.2a1.dist-info → carconnectivity_connector_seatcupra-0.2.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: carconnectivity-connector-seatcupra
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2
|
4
4
|
Summary: CarConnectivity connector for Seat and Cupra services
|
5
5
|
Author: Till Steinbach
|
6
6
|
License: MIT License
|
@@ -37,10 +37,11 @@ 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.
|
40
|
+
Requires-Dist: carconnectivity>=0.5
|
41
41
|
Requires-Dist: oauthlib~=3.2.2
|
42
42
|
Requires-Dist: requests~=2.32.3
|
43
43
|
Requires-Dist: jwt~=1.3.1
|
44
|
+
Dynamic: license-file
|
44
45
|
|
45
46
|
|
46
47
|
|
@@ -1,21 +1,21 @@
|
|
1
|
+
carconnectivity_connector_seatcupra-0.2.dist-info/licenses/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
|
1
2
|
carconnectivity_connectors/seatcupra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
carconnectivity_connectors/seatcupra/_version.py,sha256=
|
3
|
+
carconnectivity_connectors/seatcupra/_version.py,sha256=3yop_Zw31tLW5V7T20Ar9d_ywZdoSjaF0mFPUD-T2xY,506
|
3
4
|
carconnectivity_connectors/seatcupra/capability.py,sha256=936V06hOX8AuAMxL_S9wVyVa36Xw1bo9081X0xf5f94,5064
|
4
|
-
carconnectivity_connectors/seatcupra/charging.py,sha256=
|
5
|
+
carconnectivity_connectors/seatcupra/charging.py,sha256=mayvseay5x2r2qjWqol0ijlgoBL2L2A0A96T44FOiHg,4076
|
5
6
|
carconnectivity_connectors/seatcupra/climatization.py,sha256=0xxWlxrheAPzkVT8WRQtbm6ExZmVdgW7lUdOXyS_qWY,1695
|
6
7
|
carconnectivity_connectors/seatcupra/command_impl.py,sha256=LmBOCWGZPfJCG_4-5449xvO6NAvnPDsAWEBKlsG4WoI,3051
|
7
|
-
carconnectivity_connectors/seatcupra/connector.py,sha256=
|
8
|
-
carconnectivity_connectors/seatcupra/vehicle.py,sha256=
|
8
|
+
carconnectivity_connectors/seatcupra/connector.py,sha256=_8Lvg1yqHHbH4mkhThwq0KZZL64rzKoFYurQCQurqY4,130482
|
9
|
+
carconnectivity_connectors/seatcupra/vehicle.py,sha256=LHkAlVD_C8xOX81wCGFZbZqyhctpKx-CN0T3NZJ2jFk,3946
|
9
10
|
carconnectivity_connectors/seatcupra/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
11
|
carconnectivity_connectors/seatcupra/auth/auth_util.py,sha256=Y81h8fGOMSMgPtE4wI_TI9WgE_s43uaPjRLBBINhj4g,4433
|
11
|
-
carconnectivity_connectors/seatcupra/auth/my_cupra_session.py,sha256=
|
12
|
+
carconnectivity_connectors/seatcupra/auth/my_cupra_session.py,sha256=VF_9U8fESLkndVaPn2W1ZxZwNr9-ndeaegeTVT5FyYk,13904
|
12
13
|
carconnectivity_connectors/seatcupra/auth/openid_session.py,sha256=pGdTSt2zMtPWD4EY8MoZTj8lT6_krfa1Xt3Fyh877FA,16972
|
13
14
|
carconnectivity_connectors/seatcupra/auth/session_manager.py,sha256=ZIDvC848T3fy6PgGqCl8A2SzaNhu2YG19Xam5kgp7SA,5635
|
14
15
|
carconnectivity_connectors/seatcupra/auth/vw_web_session.py,sha256=CcI6m68IyRs6WsMDu-IsW3Dj85vyGiMmxvFqNETMHO0,10929
|
15
16
|
carconnectivity_connectors/seatcupra/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
|
16
17
|
carconnectivity_connectors/seatcupra/ui/connector_ui.py,sha256=SNYnlcGJpbWhuLiIHD2l6H9IfSiMz3IgmvXsdossDnE,1412
|
17
|
-
carconnectivity_connector_seatcupra-0.
|
18
|
-
carconnectivity_connector_seatcupra-0.
|
19
|
-
carconnectivity_connector_seatcupra-0.
|
20
|
-
carconnectivity_connector_seatcupra-0.
|
21
|
-
carconnectivity_connector_seatcupra-0.1.2a1.dist-info/RECORD,,
|
18
|
+
carconnectivity_connector_seatcupra-0.2.dist-info/METADATA,sha256=3RrvEwAnY_qIK95IUNMpVuc42qYt9LU9aZ-At4Qvf-g,5491
|
19
|
+
carconnectivity_connector_seatcupra-0.2.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
20
|
+
carconnectivity_connector_seatcupra-0.2.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
|
21
|
+
carconnectivity_connector_seatcupra-0.2.dist-info/RECORD,,
|
@@ -46,6 +46,7 @@ class MyCupraSession(VWWebSession):
|
|
46
46
|
|
47
47
|
self.headers = CaseInsensitiveDict({
|
48
48
|
'accept': '*/*',
|
49
|
+
'connection': 'keep-alive',
|
49
50
|
'content-type': 'application/json',
|
50
51
|
'user-agent': 'SEATApp/2.5.0 (com.seat.myseat.ola; build:202410171614; iOS 15.8.3) Alamofire/5.7.0 Mobile',
|
51
52
|
'accept-language': 'de-de',
|
@@ -62,6 +63,7 @@ class MyCupraSession(VWWebSession):
|
|
62
63
|
|
63
64
|
self.headers = CaseInsensitiveDict({
|
64
65
|
'accept': '*/*',
|
66
|
+
'connection': 'keep-alive',
|
65
67
|
'content-type': 'application/json',
|
66
68
|
'user-agent': 'CUPRAApp%20-%20Store/20220503 CFNetwork/1333.0.4 Darwin/21.5.0',
|
67
69
|
'accept-language': 'de-de',
|
@@ -220,12 +222,19 @@ class MyCupraSession(VWWebSession):
|
|
220
222
|
if headers is None:
|
221
223
|
headers = dict(self.headers)
|
222
224
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
225
|
+
if self.is_seat:
|
226
|
+
body: Dict[str, str] = {
|
227
|
+
'client_id': self.client_id,
|
228
|
+
'grant_type': 'refresh_token',
|
229
|
+
'refresh_token': self.refresh_token
|
230
|
+
}
|
231
|
+
else:
|
232
|
+
body: Dict[str, str] = {
|
233
|
+
'client_id': self.client_id,
|
234
|
+
'client_secret': 'eb8814e641c81a2640ad62eeccec11c98effc9bccd4269ab7af338b50a94b3a2',
|
235
|
+
'grant_type': 'refresh_token',
|
236
|
+
'refresh_token': self.refresh_token
|
237
|
+
}
|
229
238
|
|
230
239
|
headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8'
|
231
240
|
|
@@ -12,6 +12,8 @@ from carconnectivity.vehicle import ElectricVehicle
|
|
12
12
|
if TYPE_CHECKING:
|
13
13
|
from typing import Optional, Dict
|
14
14
|
|
15
|
+
from carconnectivity.objects import GenericObject
|
16
|
+
|
15
17
|
|
16
18
|
class SeatCupraCharging(Charging): # pylint: disable=too-many-instance-attributes
|
17
19
|
"""
|
@@ -22,9 +24,22 @@ class SeatCupraCharging(Charging): # pylint: disable=too-many-instance-attribut
|
|
22
24
|
"""
|
23
25
|
def __init__(self, vehicle: ElectricVehicle | None = None, origin: Optional[Charging] = None) -> None:
|
24
26
|
if origin is not None:
|
25
|
-
super().__init__(origin=origin)
|
27
|
+
super().__init__(vehicle=vehicle, origin=origin)
|
28
|
+
self.settings = SeatCupraCharging.Settings(parent=self, origin=origin.settings)
|
26
29
|
else:
|
27
30
|
super().__init__(vehicle=vehicle)
|
31
|
+
self.settings = SeatCupraCharging.Settings(parent=self, origin=self.settings)
|
32
|
+
|
33
|
+
class Settings(Charging.Settings):
|
34
|
+
"""
|
35
|
+
This class represents the settings for car volkswagen car charging.
|
36
|
+
"""
|
37
|
+
def __init__(self, parent: Optional[GenericObject] = None, origin: Optional[Charging.Settings] = None) -> None:
|
38
|
+
if origin is not None:
|
39
|
+
super().__init__(parent=parent, origin=origin)
|
40
|
+
else:
|
41
|
+
super().__init__(parent=parent)
|
42
|
+
self.max_current_in_ampere: Optional[bool] = None
|
28
43
|
|
29
44
|
class SeatCupraChargingState(Enum,):
|
30
45
|
"""
|
@@ -20,17 +20,20 @@ from carconnectivity.units import Length, Current
|
|
20
20
|
from carconnectivity.doors import Doors
|
21
21
|
from carconnectivity.windows import Windows
|
22
22
|
from carconnectivity.lights import Lights
|
23
|
-
from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive
|
23
|
+
from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive, DieselDrive
|
24
24
|
from carconnectivity.vehicle import GenericVehicle, ElectricVehicle
|
25
|
-
from carconnectivity.attributes import BooleanAttribute, DurationAttribute, GenericAttribute, TemperatureAttribute, EnumAttribute
|
25
|
+
from carconnectivity.attributes import BooleanAttribute, DurationAttribute, GenericAttribute, TemperatureAttribute, EnumAttribute, CurrentAttribute, \
|
26
|
+
LevelAttribute
|
26
27
|
from carconnectivity.units import Temperature
|
27
|
-
from carconnectivity.command_impl import ClimatizationStartStopCommand, WakeSleepCommand, HonkAndFlashCommand, LockUnlockCommand, ChargingStartStopCommand
|
28
|
+
from carconnectivity.command_impl import ClimatizationStartStopCommand, WakeSleepCommand, HonkAndFlashCommand, LockUnlockCommand, ChargingStartStopCommand, \
|
29
|
+
WindowHeatingStartStopCommand
|
28
30
|
from carconnectivity.climatization import Climatization
|
29
31
|
from carconnectivity.commands import Commands
|
30
32
|
from carconnectivity.charging import Charging
|
31
33
|
from carconnectivity.charging_connector import ChargingConnector
|
32
34
|
from carconnectivity.position import Position
|
33
35
|
from carconnectivity.enums import ConnectionState
|
36
|
+
from carconnectivity.window_heating import WindowHeatings
|
34
37
|
|
35
38
|
from carconnectivity_connectors.base.connector import BaseConnector
|
36
39
|
from carconnectivity_connectors.seatcupra.auth.session_manager import SessionManager, SessionUser, Service
|
@@ -288,6 +291,7 @@ class Connector(BaseConnector):
|
|
288
291
|
vehicle_to_update = self.fetch_vehicle_status(vehicle_to_update)
|
289
292
|
vehicle_to_update = self.fetch_vehicle_mycar_status(vehicle_to_update)
|
290
293
|
vehicle_to_update = self.fetch_mileage(vehicle_to_update)
|
294
|
+
vehicle_to_update = self.fetch_ranges(vehicle_to_update)
|
291
295
|
if vehicle_to_update.capabilities.has_capability('climatisation', check_status_ok=True):
|
292
296
|
vehicle_to_update = self.fetch_climatisation(vehicle_to_update)
|
293
297
|
if vehicle_to_update.capabilities.has_capability('charging', check_status_ok=True):
|
@@ -414,7 +418,7 @@ class Connector(BaseConnector):
|
|
414
418
|
capability.parameters[parameter] = value
|
415
419
|
else:
|
416
420
|
raise APIError('Could not fetch capabilities, capability ID missing')
|
417
|
-
log_extra_keys(LOG_API, 'capability', capability_dict, {'id', 'expirationDate', 'editable', 'parameters'})
|
421
|
+
log_extra_keys(LOG_API, 'capability', capability_dict, {'id', 'expirationDate', 'editable', 'parameters', 'status'})
|
418
422
|
|
419
423
|
for capability_id in vehicle.capabilities.capabilities.keys() - found_capabilities:
|
420
424
|
vehicle.capabilities.remove_capability(capability_id)
|
@@ -422,7 +426,7 @@ class Connector(BaseConnector):
|
|
422
426
|
if vehicle.capabilities.has_capability('charging', check_status_ok=True):
|
423
427
|
if not isinstance(vehicle, SeatCupraElectricVehicle):
|
424
428
|
LOG.debug('Promoting %s to SeatCupraElectricVehicle object for %s', vehicle.__class__.__name__, vin)
|
425
|
-
vehicle = SeatCupraElectricVehicle(origin=vehicle)
|
429
|
+
vehicle = SeatCupraElectricVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
426
430
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
427
431
|
if not vehicle.charging.commands.contains_command('start-stop'):
|
428
432
|
charging_start_stop_command: ChargingStartStopCommand = ChargingStartStopCommand(parent=vehicle.charging.commands)
|
@@ -646,6 +650,8 @@ class Connector(BaseConnector):
|
|
646
650
|
else:
|
647
651
|
if engine_type == GenericDrive.Type.ELECTRIC:
|
648
652
|
drive = ElectricDrive(drive_id=drive_id, drives=vehicle.drives)
|
653
|
+
elif engine_type == GenericDrive.Type.DIESEL:
|
654
|
+
drive = DieselDrive(drive_id=drive_id, drives=vehicle.drives)
|
649
655
|
elif engine_type in [GenericDrive.Type.FUEL,
|
650
656
|
GenericDrive.Type.GASOLINE,
|
651
657
|
GenericDrive.Type.PETROL,
|
@@ -684,15 +690,15 @@ class Connector(BaseConnector):
|
|
684
690
|
has_combustion = True
|
685
691
|
if has_electric and not has_combustion and not isinstance(vehicle, SeatCupraElectricVehicle):
|
686
692
|
LOG.debug('Promoting %s to SeatCupraElectricVehicle object for %s', vehicle.__class__.__name__, vin)
|
687
|
-
vehicle = SeatCupraElectricVehicle(origin=vehicle)
|
693
|
+
vehicle = SeatCupraElectricVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
688
694
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
689
695
|
elif has_combustion and not has_electric and not isinstance(vehicle, SeatCupraCombustionVehicle):
|
690
696
|
LOG.debug('Promoting %s to SeatCupraCombustionVehicle object for %s', vehicle.__class__.__name__, vin)
|
691
|
-
vehicle = SeatCupraCombustionVehicle(origin=vehicle)
|
697
|
+
vehicle = SeatCupraCombustionVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
692
698
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
693
699
|
elif has_combustion and has_electric and not isinstance(vehicle, SeatCupraHybridVehicle):
|
694
700
|
LOG.debug('Promoting %s to SeatCupraHybridVehicle object for %s', vehicle.__class__.__name__, vin)
|
695
|
-
vehicle = SeatCupraHybridVehicle(origin=vehicle)
|
701
|
+
vehicle = SeatCupraHybridVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
696
702
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
697
703
|
if 'services' in vehicle_status_data and vehicle_status_data['services'] is not None:
|
698
704
|
if 'charging' in vehicle_status_data['services'] and vehicle_status_data['services']['charging'] is not None:
|
@@ -845,6 +851,40 @@ class Connector(BaseConnector):
|
|
845
851
|
vehicle.odometer._set_value(None) # pylint: disable=protected-access
|
846
852
|
return vehicle
|
847
853
|
|
854
|
+
def fetch_ranges(self, vehicle: SeatCupraVehicle, no_cache: bool = False) -> SeatCupraVehicle:
|
855
|
+
vin = vehicle.vin.value
|
856
|
+
if vin is None:
|
857
|
+
raise APIError('VIN is missing')
|
858
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/ranges'
|
859
|
+
# {'ranges': [{'rangeName': 'gasolineRangeKm', 'value': 100.0}, {'rangeName': 'electricRangeKm', 'value': 28.0}]}
|
860
|
+
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
861
|
+
if data is not None:
|
862
|
+
if 'ranges' in data and data['ranges'] is not None:
|
863
|
+
for drive in vehicle.drives.drives.values():
|
864
|
+
if drive.type.enabled and drive.type.value == GenericDrive.Type.ELECTRIC:
|
865
|
+
for range_dict in data['ranges']:
|
866
|
+
if 'rangeName' in range_dict and range_dict['rangeName'] is not None and range_dict['rangeName'] == 'electricRangeKm' \
|
867
|
+
and 'value' in range_dict and range_dict['value'] is not None:
|
868
|
+
drive.range._set_value(range_dict['value'], unit=Length.KM) # pylint: disable=protected-access
|
869
|
+
break
|
870
|
+
elif drive.type.enabled and drive.type.value == GenericDrive.Type.GASOLINE:
|
871
|
+
for range_dict in data['ranges']:
|
872
|
+
if 'rangeName' in range_dict and range_dict['rangeName'] is not None and range_dict['rangeName'] == 'gasolineRangeKm' \
|
873
|
+
and 'value' in range_dict and range_dict['value'] is not None:
|
874
|
+
drive.range._set_value(range_dict['value'], unit=Length.KM) # pylint: disable=protected-access
|
875
|
+
break
|
876
|
+
elif drive.type.enabled and drive.type.value == GenericDrive.Type.DIESEL:
|
877
|
+
for range_dict in data['ranges']:
|
878
|
+
if 'rangeName' in range_dict and range_dict['rangeName'] is not None and range_dict['rangeName'] == 'dieselRangeKm' \
|
879
|
+
and 'value' in range_dict and range_dict['value'] is not None:
|
880
|
+
drive.range._set_value(range_dict['value'], unit=Length.KM) # pylint: disable=protected-access
|
881
|
+
elif 'rangeName' in range_dict and range_dict['rangeName'] is not None and range_dict['rangeName'] == 'adBlueKm' \
|
882
|
+
and 'value' in range_dict and range_dict['value'] is not None:
|
883
|
+
if isinstance(drive, DieselDrive):
|
884
|
+
drive.adblue_range._set_value(range_dict['value'], unit=Length.KM) # pylint: disable=protected-access
|
885
|
+
log_extra_keys(LOG_API, f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/ranges', data, {'ranges'})
|
886
|
+
return vehicle
|
887
|
+
|
848
888
|
def fetch_maintenance(self, vehicle: SeatCupraVehicle, no_cache: bool = False) -> SeatCupraVehicle:
|
849
889
|
vin = vehicle.vin.value
|
850
890
|
if vin is None:
|
@@ -921,7 +961,57 @@ class Connector(BaseConnector):
|
|
921
961
|
log_extra_keys(LOG_API, 'climatisationStatus', data['climatisationStatus'], {'carCapturedTimestamp', 'climatisationState'})
|
922
962
|
else:
|
923
963
|
vehicle.climatization.state._set_value(None) # pylint: disable=protected-access
|
924
|
-
|
964
|
+
if 'windowHeatingStatus' in data and data['windowHeatingStatus'] is not None:
|
965
|
+
window_heating_status: Dict = data['windowHeatingStatus']
|
966
|
+
if 'carCapturedTimestamp' not in window_heating_status or window_heating_status['carCapturedTimestamp'] is None:
|
967
|
+
raise APIError('Could not fetch vehicle status, carCapturedTimestamp missing')
|
968
|
+
captured_at: datetime = robust_time_parse(window_heating_status['carCapturedTimestamp'])
|
969
|
+
if 'windowHeatingStatus' in window_heating_status and window_heating_status['windowHeatingStatus'] is not None:
|
970
|
+
heating_on: bool = False
|
971
|
+
all_heating_invalid: bool = True
|
972
|
+
for window_heating in window_heating_status['windowHeatingStatus']:
|
973
|
+
if 'windowLocation' in window_heating and window_heating['windowLocation'] is not None:
|
974
|
+
window_id = window_heating['windowLocation']
|
975
|
+
if window_id in vehicle.window_heatings.windows:
|
976
|
+
window: WindowHeatings.WindowHeating = vehicle.window_heatings.windows[window_id]
|
977
|
+
else:
|
978
|
+
window = WindowHeatings.WindowHeating(window_id=window_id, window_heatings=vehicle.window_heatings)
|
979
|
+
vehicle.window_heatings.windows[window_id] = window
|
980
|
+
if 'windowHeatingState' in window_heating and window_heating['windowHeatingState'] is not None:
|
981
|
+
if window_heating['windowHeatingState'] in [item.value for item in WindowHeatings.HeatingState]:
|
982
|
+
window_heating_state: WindowHeatings.HeatingState = WindowHeatings.HeatingState(window_heating['windowHeatingState'])
|
983
|
+
if window_heating_state == WindowHeatings.HeatingState.ON:
|
984
|
+
heating_on = True
|
985
|
+
if window_heating_state in [WindowHeatings.HeatingState.ON,
|
986
|
+
WindowHeatings.HeatingState.OFF]:
|
987
|
+
all_heating_invalid = False
|
988
|
+
window.heating_state._set_value(window_heating_state, measured=captured_at) # pylint: disable=protected-access
|
989
|
+
else:
|
990
|
+
LOG_API.info('Unknown window heating state %s not in %s', window_heating['windowHeatingState'],
|
991
|
+
str(WindowHeatings.HeatingState))
|
992
|
+
# pylint: disable-next=protected-access
|
993
|
+
window.heating_state._set_value(WindowHeatings.HeatingState.UNKNOWN, measured=captured_at)
|
994
|
+
else:
|
995
|
+
window.heating_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
996
|
+
log_extra_keys(LOG_API, 'windowHeatingStatus', window_heating, {'windowLocation', 'windowHeatingState'})
|
997
|
+
if all_heating_invalid:
|
998
|
+
# pylint: disable-next=protected-access
|
999
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.INVALID, measured=captured_at)
|
1000
|
+
else:
|
1001
|
+
if heating_on:
|
1002
|
+
# pylint: disable-next=protected-access
|
1003
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.ON, measured=captured_at)
|
1004
|
+
else:
|
1005
|
+
# pylint: disable-next=protected-access
|
1006
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.OFF, measured=captured_at)
|
1007
|
+
if vehicle.window_heatings is not None and vehicle.window_heatings.commands is not None \
|
1008
|
+
and not vehicle.window_heatings.commands.contains_command('start-stop'):
|
1009
|
+
start_stop_command = WindowHeatingStartStopCommand(parent=vehicle.window_heatings.commands)
|
1010
|
+
start_stop_command._add_on_set_hook(self.__on_window_heating_start_stop) # pylint: disable=protected-access
|
1011
|
+
start_stop_command.enabled = True
|
1012
|
+
vehicle.window_heatings.commands.add_command(start_stop_command)
|
1013
|
+
log_extra_keys(LOG_API, 'windowHeatingStatus', window_heating_status, {'carCapturedTimestamp', 'windowHeatingStatus'})
|
1014
|
+
log_extra_keys(LOG_API, 'climatisation', data, {'climatisationStatus', 'windowHeatingStatus'})
|
925
1015
|
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/vehicles/{vin}/climatisation/settings'
|
926
1016
|
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
927
1017
|
if data is not None:
|
@@ -1043,22 +1133,84 @@ class Connector(BaseConnector):
|
|
1043
1133
|
log_extra_keys(LOG_API, f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/charging/status', data,
|
1044
1134
|
{'state', 'battery', 'charging', 'plug'})
|
1045
1135
|
|
1046
|
-
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/
|
1136
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/settings'
|
1047
1137
|
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
1048
1138
|
if data is not None:
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1139
|
+
# {'settings': {'maxChargeCurrentAC': 'reduced', 'carCapturedTimestamp': '2025-03-18T16:50:33Z', 'autoUnlockPlugWhenCharged': None, 'targetSoc_pct': 100, 'batteryCareTargetSocPercentage': 80}}
|
1140
|
+
if 'settings' in data and data['settings'] is not None:
|
1141
|
+
if 'carCapturedTimestamp' not in data['settings'] or data['settings']['carCapturedTimestamp'] is None:
|
1142
|
+
raise APIError('Could not fetch vehicle status, carCapturedTimestamp missing')
|
1143
|
+
captured_at: datetime = robust_time_parse(data['settings']['carCapturedTimestamp'])
|
1144
|
+
if 'maxChargeCurrentAC_A' in data['settings'] and data['settings']['maxChargeCurrentAC_A'] is not None:
|
1145
|
+
if isinstance(vehicle.charging.settings, SeatCupraCharging.Settings):
|
1146
|
+
vehicle.charging.settings.max_current_in_ampere = True
|
1147
|
+
else:
|
1148
|
+
raise ValueError('Charging settings not of type VolkswagenCharging.Settings')
|
1149
|
+
vehicle.charging.settings.maximum_current.minimum = 6.0
|
1150
|
+
vehicle.charging.settings.maximum_current.maximum = 16.0
|
1151
|
+
vehicle.charging.settings.maximum_current.precision = 1.0
|
1152
|
+
# pylint: disable-next=protected-access
|
1153
|
+
vehicle.charging.settings.maximum_current._add_on_set_hook(self.__on_charging_settings_change)
|
1154
|
+
vehicle.charging.settings.maximum_current._is_changeable = True # pylint: disable=protected-access
|
1155
|
+
vehicle.charging.settings.maximum_current._set_value(data['settings']['maxChargeCurrentAC_A'], # pylint: disable=protected-access
|
1156
|
+
measured=captured_at)
|
1157
|
+
elif 'maxChargeCurrentAC' in data['settings'] and data['settings']['maxChargeCurrentAC'] is not None:
|
1158
|
+
if isinstance(vehicle.charging.settings, SeatCupraCharging.Settings):
|
1159
|
+
vehicle.charging.settings.max_current_in_ampere = False
|
1160
|
+
else:
|
1161
|
+
raise ValueError('Charging settings not of type VolkswagenCharging.Settings')
|
1162
|
+
vehicle.charging.settings.maximum_current.minimum = 6.0
|
1163
|
+
vehicle.charging.settings.maximum_current.maximum = 16.0
|
1164
|
+
vehicle.charging.settings.maximum_current.precision = 1.0
|
1165
|
+
# pylint: disable-next=protected-access
|
1166
|
+
vehicle.charging.settings.maximum_current._add_on_set_hook(self.__on_charging_settings_change)
|
1167
|
+
vehicle.charging.settings.maximum_current._is_changeable = True # pylint: disable=protected-access
|
1168
|
+
if data['settings']['maxChargeCurrentAC'] == 'maximum':
|
1169
|
+
vehicle.charging.settings.maximum_current._set_value(16.0, # pylint: disable=protected-access
|
1170
|
+
measured=captured_at)
|
1171
|
+
elif data['settings']['maxChargeCurrentAC'] == 'reduced':
|
1172
|
+
vehicle.charging.settings.maximum_current._set_value(6.0, # pylint: disable=protected-access
|
1173
|
+
measured=captured_at)
|
1174
|
+
else:
|
1175
|
+
LOG_API.info('Unknown max charge current %s', data['settings']['maxChargeCurrentAC'])
|
1176
|
+
vehicle.charging.settings.maximum_current._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
1053
1177
|
else:
|
1054
|
-
vehicle.charging.settings.maximum_current._set_value(
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1178
|
+
vehicle.charging.settings.maximum_current._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
1179
|
+
if 'autoUnlockPlugWhenCharged' in data['settings'] and data['settings']['autoUnlockPlugWhenCharged'] is not None:
|
1180
|
+
# pylint: disable-next=protected-access
|
1181
|
+
vehicle.charging.settings.auto_unlock._add_on_set_hook(self.__on_charging_settings_change)
|
1182
|
+
vehicle.charging.settings.auto_unlock._is_changeable = True # pylint: disable=protected-access
|
1183
|
+
if data['settings']['autoUnlockPlugWhenCharged'] == 'on':
|
1184
|
+
vehicle.charging.settings.auto_unlock._set_value(True, # pylint: disable=protected-access
|
1185
|
+
measured=captured_at)
|
1186
|
+
elif data['settings']['autoUnlockPlugWhenCharged'] == 'off':
|
1187
|
+
vehicle.charging.settings.auto_unlock._set_value(False, # pylint: disable=protected-access
|
1188
|
+
measured=captured_at)
|
1189
|
+
else:
|
1190
|
+
LOG_API.info('Unknown auto unlock plug when charged %s', data['settings']['autoUnlockPlugWhenCharged'])
|
1191
|
+
vehicle.charging.settings.auto_unlock._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
1192
|
+
else:
|
1193
|
+
vehicle.charging.settings.auto_unlock._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
1194
|
+
if 'targetSoc_pct' in data['settings'] and data['settings']['targetSoc_pct'] is not None:
|
1195
|
+
charging_capability: Optional[Capability] = vehicle.capabilities.get_capability('charging')
|
1196
|
+
if charging_capability is not None and ('supportsTargetStateOfCharge' not in charging_capability.parameters
|
1197
|
+
or charging_capability.parameters['supportsTargetStateOfCharge'] != 'false'):
|
1198
|
+
vehicle.charging.settings.target_level.minimum = 50.0
|
1199
|
+
vehicle.charging.settings.target_level.maximum = 100.0
|
1200
|
+
vehicle.charging.settings.target_level.precision = 10.0
|
1201
|
+
# pylint: disable-next=protected-access
|
1202
|
+
vehicle.charging.settings.target_level._add_on_set_hook(self.__on_charging_settings_change)
|
1203
|
+
vehicle.charging.settings.target_level._is_changeable = True # pylint: disable=protected-access
|
1204
|
+
vehicle.charging.settings.target_level._set_value(data['settings']['targetSoc_pct'], # pylint: disable=protected-access
|
1205
|
+
measured=captured_at)
|
1206
|
+
else:
|
1207
|
+
vehicle.charging.settings.target_level._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
1208
|
+
log_extra_keys(LOG_API, 'chargingSettings', data['settings'], {'carCapturedTimestamp', 'maxChargeCurrentAC_A', 'maxChargeCurrentAC',
|
1209
|
+
'autoUnlockPlugWhenCharged', 'targetSoc_pct'})
|
1210
|
+
else:
|
1211
|
+
vehicle.charging.settings.maximum_current._set_value(None) # pylint: disable=protected-access
|
1212
|
+
vehicle.charging.settings.auto_unlock._set_value(None) # pylint: disable=protected-access
|
1213
|
+
vehicle.charging.settings.target_level._set_value(None) # pylint: disable=protected-access
|
1062
1214
|
return vehicle
|
1063
1215
|
|
1064
1216
|
def fetch_image(self, vehicle: SeatCupraVehicle, no_cache: bool = False) -> SeatCupraVehicle:
|
@@ -1205,7 +1357,6 @@ class Connector(BaseConnector):
|
|
1205
1357
|
raise CommandError('VIN in object hierarchy missing')
|
1206
1358
|
if 'command' not in command_arguments:
|
1207
1359
|
raise CommandError('Command argument missing')
|
1208
|
-
command_dict: Dict = {}
|
1209
1360
|
try:
|
1210
1361
|
if command_arguments['command'] == ChargingStartStopCommand.Command.START:
|
1211
1362
|
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/start'
|
@@ -1494,20 +1645,25 @@ class Connector(BaseConnector):
|
|
1494
1645
|
if settings.target_temperature.enabled and settings.target_temperature.value is not None:
|
1495
1646
|
# Round target temperature to nearest 0.5
|
1496
1647
|
# Check if the attribute changed is the target_temperature attribute
|
1648
|
+
precision: float = settings.target_temperature.precision if settings.target_temperature.precision is not None else 0.5
|
1497
1649
|
if isinstance(attribute, TemperatureAttribute) and attribute.id == 'target_temperature':
|
1498
|
-
|
1650
|
+
value = round(value / settings.target_temperature.precision) * settings.target_temperature.precision
|
1651
|
+
setting_dict['targetTemperature'] = value
|
1499
1652
|
else:
|
1500
|
-
setting_dict['targetTemperature'] = round(settings.target_temperature.value
|
1653
|
+
setting_dict['targetTemperature'] = round(settings.target_temperature.value / precision) * precision
|
1501
1654
|
if settings.target_temperature.unit == Temperature.C:
|
1502
1655
|
setting_dict['targetTemperatureUnit'] = 'celsius'
|
1503
1656
|
elif settings.target_temperature.unit == Temperature.F:
|
1504
1657
|
setting_dict['targetTemperatureUnit'] = 'farenheit'
|
1505
1658
|
else:
|
1506
1659
|
setting_dict['targetTemperatureUnit'] = 'celsius'
|
1507
|
-
|
1508
|
-
|
1509
|
-
|
1510
|
-
|
1660
|
+
climatization_capability: Optional[Capability] = vehicle.capabilities.get_capability('climatisation')
|
1661
|
+
if climatization_capability is not None and ('supportsOffGridClimatisation' not in climatization_capability.parameters
|
1662
|
+
or climatization_capability.parameters['supportsOffGridClimatisation'] != 'false'):
|
1663
|
+
if isinstance(attribute, BooleanAttribute) and attribute.id == 'climatisation_without_external_power':
|
1664
|
+
setting_dict['climatisationWithoutExternalPower'] = value
|
1665
|
+
elif settings.climatization_without_external_power.enabled and settings.climatization_without_external_power.value is not None:
|
1666
|
+
setting_dict['climatisationWithoutExternalPower'] = settings.climatization_without_external_power.value
|
1511
1667
|
|
1512
1668
|
url: str = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/vehicles/{vin}/climatisation/settings'
|
1513
1669
|
try:
|
@@ -1526,6 +1682,114 @@ class Connector(BaseConnector):
|
|
1526
1682
|
raise SetterError(f'Retrying failed: {retry_error}') from retry_error
|
1527
1683
|
return value
|
1528
1684
|
|
1685
|
+
def __on_window_heating_start_stop(self, start_stop_command: WindowHeatingStartStopCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
1686
|
+
-> Union[str, Dict[str, Any]]:
|
1687
|
+
if start_stop_command.parent is None or start_stop_command.parent.parent is None \
|
1688
|
+
or start_stop_command.parent.parent.parent is None or not isinstance(start_stop_command.parent.parent.parent, SeatCupraVehicle):
|
1689
|
+
raise CommandError('Object hierarchy is not as expected')
|
1690
|
+
if not isinstance(command_arguments, dict):
|
1691
|
+
raise CommandError('Command arguments are not a dictionary')
|
1692
|
+
vehicle: SeatCupraVehicle = start_stop_command.parent.parent.parent
|
1693
|
+
vin: Optional[str] = vehicle.vin.value
|
1694
|
+
if vin is None:
|
1695
|
+
raise CommandError('VIN in object hierarchy missing')
|
1696
|
+
if 'command' not in command_arguments:
|
1697
|
+
raise CommandError('Command argument missing')
|
1698
|
+
try:
|
1699
|
+
if command_arguments['command'] == WindowHeatingStartStopCommand.Command.START:
|
1700
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/windowheating/requests/start'
|
1701
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
1702
|
+
elif command_arguments['command'] == WindowHeatingStartStopCommand.Command.STOP:
|
1703
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/windowheating/requests/stop'
|
1704
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
1705
|
+
else:
|
1706
|
+
raise CommandError(f'Unknown command {command_arguments["command"]}')
|
1707
|
+
|
1708
|
+
if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
|
1709
|
+
LOG.error('Could not start/stop window heating (%s: %s)', command_response.status_code, command_response.text)
|
1710
|
+
raise CommandError(f'Could not start/stop window heating ({command_response.status_code}: {command_response.text})')
|
1711
|
+
except requests.exceptions.ConnectionError as connection_error:
|
1712
|
+
raise CommandError(f'Connection error: {connection_error}.'
|
1713
|
+
' If this happens frequently, please check if other applications communicate with the Seat/Cupra server.') from connection_error
|
1714
|
+
except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
|
1715
|
+
raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
|
1716
|
+
except requests.exceptions.ReadTimeout as timeout_error:
|
1717
|
+
raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
|
1718
|
+
except requests.exceptions.RetryError as retry_error:
|
1719
|
+
raise CommandError(f'Retrying failed: {retry_error}') from retry_error
|
1720
|
+
return command_arguments
|
1721
|
+
|
1722
|
+
def __on_charging_settings_change(self, attribute: GenericAttribute, value: Any) -> Any:
|
1723
|
+
"""
|
1724
|
+
Callback for the charging setting change.
|
1725
|
+
"""
|
1726
|
+
if attribute.parent is None or not isinstance(attribute.parent, SeatCupraCharging.Settings) \
|
1727
|
+
or attribute.parent.parent is None \
|
1728
|
+
or attribute.parent.parent.parent is None or not isinstance(attribute.parent.parent.parent, SeatCupraVehicle):
|
1729
|
+
raise SetterError('Object hierarchy is not as expected')
|
1730
|
+
settings: SeatCupraCharging.Settings = attribute.parent
|
1731
|
+
vehicle: SeatCupraVehicle = attribute.parent.parent.parent
|
1732
|
+
vin: Optional[str] = vehicle.vin.value
|
1733
|
+
if vin is None:
|
1734
|
+
raise SetterError('VIN in object hierarchy missing')
|
1735
|
+
setting_dict = {}
|
1736
|
+
precision: float = settings.maximum_current.precision if settings.maximum_current.precision is not None else 1.0
|
1737
|
+
if isinstance(attribute, CurrentAttribute) and attribute.id == 'maximum_current':
|
1738
|
+
value = round(value / precision) * precision
|
1739
|
+
if settings.max_current_in_ampere:
|
1740
|
+
setting_dict['maxChargeCurrentAcInAmperes'] = value
|
1741
|
+
else:
|
1742
|
+
if value < 6:
|
1743
|
+
raise SetterError('Maximum current must be greater than 6 amps')
|
1744
|
+
if value < 16:
|
1745
|
+
setting_dict['maxChargeCurrentAc'] = 'reduced'
|
1746
|
+
value = 6.0
|
1747
|
+
else:
|
1748
|
+
setting_dict['maxChargeCurrentAc'] = 'maximum'
|
1749
|
+
value = 16.0
|
1750
|
+
elif settings.maximum_current.enabled and settings.maximum_current.value is not None:
|
1751
|
+
if settings.max_current_in_ampere:
|
1752
|
+
setting_dict['maxChargeCurrentAc_A'] = round(settings.maximum_current.value / precision) * precision
|
1753
|
+
else:
|
1754
|
+
if settings.maximum_current.value < 6:
|
1755
|
+
raise SetterError('Maximum current must be greater than 6 amps')
|
1756
|
+
if settings.maximum_current.value < 16:
|
1757
|
+
setting_dict['maxChargeCurrentAc'] = 'reduced'
|
1758
|
+
settings.maximum_current.value = 6.0
|
1759
|
+
else:
|
1760
|
+
setting_dict['maxChargeCurrentAc'] = 'maximum'
|
1761
|
+
settings.maximum_current.value = 16.0
|
1762
|
+
if isinstance(attribute, BooleanAttribute) and attribute.id == 'auto_unlock':
|
1763
|
+
setting_dict['autoUnlockPlugWhenChargedAc'] = 'on' if value else 'off'
|
1764
|
+
elif settings.auto_unlock.enabled and settings.auto_unlock.value is not None:
|
1765
|
+
setting_dict['autoUnlockPlugWhenChargedAc'] = 'on' if settings.auto_unlock.value else 'off'
|
1766
|
+
charging_capability: Optional[Capability] = vehicle.capabilities.get_capability('charging')
|
1767
|
+
if charging_capability is not None and ('supportsTargetStateOfCharge' not in charging_capability.parameters
|
1768
|
+
or charging_capability.parameters['supportsTargetStateOfCharge'] != 'false'):
|
1769
|
+
precision: float = settings.target_level.precision if settings.target_level.precision is not None else 10.0
|
1770
|
+
if isinstance(attribute, LevelAttribute) and attribute.id == 'target_level':
|
1771
|
+
value = round(value / precision) * precision
|
1772
|
+
setting_dict['targetSoc'] = value
|
1773
|
+
elif settings.target_level.enabled and settings.target_level.value is not None:
|
1774
|
+
setting_dict['targetSoc'] = round(settings.target_level.value / precision) * precision
|
1775
|
+
|
1776
|
+
url: str = f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/charging/settings'
|
1777
|
+
try:
|
1778
|
+
settings_response: requests.Response = self.session.post(url, data=json.dumps(setting_dict), allow_redirects=True)
|
1779
|
+
if settings_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
|
1780
|
+
LOG.error('Could not set charging settings (%s)', settings_response.status_code)
|
1781
|
+
raise SetterError(f'Could not set value ({settings_response.status_code})')
|
1782
|
+
except requests.exceptions.ConnectionError as connection_error:
|
1783
|
+
raise SetterError(f'Connection error: {connection_error}.'
|
1784
|
+
' If this happens frequently, please check if other applications communicate with the Volkswagen server.') from connection_error
|
1785
|
+
except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
|
1786
|
+
raise SetterError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
|
1787
|
+
except requests.exceptions.ReadTimeout as timeout_error:
|
1788
|
+
raise SetterError(f'Timeout during read: {timeout_error}') from timeout_error
|
1789
|
+
except requests.exceptions.RetryError as retry_error:
|
1790
|
+
raise SetterError(f'Retrying failed: {retry_error}') from retry_error
|
1791
|
+
return value
|
1792
|
+
|
1529
1793
|
def get_version(self) -> str:
|
1530
1794
|
return __version__
|
1531
1795
|
|
@@ -6,6 +6,7 @@ from carconnectivity.vehicle import GenericVehicle, ElectricVehicle, CombustionV
|
|
6
6
|
|
7
7
|
from carconnectivity_connectors.seatcupra.capability import Capabilities
|
8
8
|
from carconnectivity_connectors.seatcupra.climatization import SeatCupraClimatization
|
9
|
+
from carconnectivity_connectors.seatcupra.charging import SeatCupraCharging
|
9
10
|
|
10
11
|
SUPPORT_IMAGES = False
|
11
12
|
try:
|
@@ -17,6 +18,8 @@ except ImportError:
|
|
17
18
|
if TYPE_CHECKING:
|
18
19
|
from typing import Optional, Dict
|
19
20
|
from carconnectivity.garage import Garage
|
21
|
+
from carconnectivity.charging import Charging
|
22
|
+
|
20
23
|
from carconnectivity_connectors.base.connector import BaseConnector
|
21
24
|
|
22
25
|
|
@@ -34,7 +37,7 @@ class SeatCupraVehicle(GenericVehicle): # pylint: disable=too-many-instance-att
|
|
34
37
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
35
38
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
36
39
|
if origin is not None:
|
37
|
-
super().__init__(origin=origin)
|
40
|
+
super().__init__(garage=garage, origin=origin)
|
38
41
|
self.capabilities: Capabilities = origin.capabilities
|
39
42
|
self.capabilities.parent = self
|
40
43
|
if SUPPORT_IMAGES:
|
@@ -54,9 +57,14 @@ class SeatCupraElectricVehicle(ElectricVehicle, SeatCupraVehicle):
|
|
54
57
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
55
58
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
56
59
|
if origin is not None:
|
57
|
-
super().__init__(origin=origin)
|
60
|
+
super().__init__(garage=garage, origin=origin)
|
61
|
+
if isinstance(origin, ElectricVehicle):
|
62
|
+
self.charging: Charging = SeatCupraCharging(vehicle=self, origin=origin.charging)
|
63
|
+
else:
|
64
|
+
self.charging: Charging = SeatCupraCharging(vehicle=self, origin=self.charging)
|
58
65
|
else:
|
59
66
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
67
|
+
self.charging: Charging = SeatCupraCharging(vehicle=self, origin=self.charging)
|
60
68
|
|
61
69
|
|
62
70
|
class SeatCupraCombustionVehicle(CombustionVehicle, SeatCupraVehicle):
|
@@ -66,7 +74,7 @@ class SeatCupraCombustionVehicle(CombustionVehicle, SeatCupraVehicle):
|
|
66
74
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
67
75
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
68
76
|
if origin is not None:
|
69
|
-
super().__init__(origin=origin)
|
77
|
+
super().__init__(garage=garage, origin=origin)
|
70
78
|
else:
|
71
79
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
72
80
|
|
@@ -78,6 +86,6 @@ class SeatCupraHybridVehicle(HybridVehicle, SeatCupraVehicle):
|
|
78
86
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
79
87
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
80
88
|
if origin is not None:
|
81
|
-
super().__init__(origin=origin)
|
89
|
+
super().__init__(garage=garage, origin=origin)
|
82
90
|
else:
|
83
91
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
File without changes
|