carconnectivity-connector-seatcupra 0.2a2__py3-none-any.whl → 0.2a4__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.2a2.dist-info → carconnectivity_connector_seatcupra-0.2a4.dist-info}/METADATA +2 -2
- {carconnectivity_connector_seatcupra-0.2a2.dist-info → carconnectivity_connector_seatcupra-0.2a4.dist-info}/RECORD +8 -8
- carconnectivity_connectors/seatcupra/_version.py +1 -1
- carconnectivity_connectors/seatcupra/connector.py +99 -9
- carconnectivity_connectors/seatcupra/vehicle.py +4 -4
- {carconnectivity_connector_seatcupra-0.2a2.dist-info → carconnectivity_connector_seatcupra-0.2a4.dist-info}/LICENSE +0 -0
- {carconnectivity_connector_seatcupra-0.2a2.dist-info → carconnectivity_connector_seatcupra-0.2a4.dist-info}/WHEEL +0 -0
- {carconnectivity_connector_seatcupra-0.2a2.dist-info → carconnectivity_connector_seatcupra-0.2a4.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: carconnectivity-connector-seatcupra
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2a4
|
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.
|
40
|
+
Requires-Dist: carconnectivity>=0.5a4
|
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,11 +1,11 @@
|
|
1
1
|
carconnectivity_connectors/seatcupra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
carconnectivity_connectors/seatcupra/_version.py,sha256=
|
2
|
+
carconnectivity_connectors/seatcupra/_version.py,sha256=tfKjOgkysWzsCAchrdls12fBGPdso8aTKDZv71JrhH4,508
|
3
3
|
carconnectivity_connectors/seatcupra/capability.py,sha256=936V06hOX8AuAMxL_S9wVyVa36Xw1bo9081X0xf5f94,5064
|
4
4
|
carconnectivity_connectors/seatcupra/charging.py,sha256=BJe_5GEB0JkP78tpU6kyKpwuwjDZHvm-kt3PTlpQHeU,3336
|
5
5
|
carconnectivity_connectors/seatcupra/climatization.py,sha256=0xxWlxrheAPzkVT8WRQtbm6ExZmVdgW7lUdOXyS_qWY,1695
|
6
6
|
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
|
7
|
+
carconnectivity_connectors/seatcupra/connector.py,sha256=PoTAAWKbToQ_a7VTLnfS2vDyxdj_mZ_dNZjs0YK7xYk,118807
|
8
|
+
carconnectivity_connectors/seatcupra/vehicle.py,sha256=-M_d1Boly5DLJSQT_Zc8R3JJ7Csi_M4kktgGqjTrPAQ,3463
|
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
|
11
11
|
carconnectivity_connectors/seatcupra/auth/my_cupra_session.py,sha256=VF_9U8fESLkndVaPn2W1ZxZwNr9-ndeaegeTVT5FyYk,13904
|
@@ -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.
|
18
|
-
carconnectivity_connector_seatcupra-0.
|
19
|
-
carconnectivity_connector_seatcupra-0.
|
20
|
-
carconnectivity_connector_seatcupra-0.
|
21
|
-
carconnectivity_connector_seatcupra-0.
|
17
|
+
carconnectivity_connector_seatcupra-0.2a4.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
|
18
|
+
carconnectivity_connector_seatcupra-0.2a4.dist-info/METADATA,sha256=6DlLIQCvCZlpR_8QEC6_ksBczkiLvjIUm_097x-95mY,5473
|
19
|
+
carconnectivity_connector_seatcupra-0.2a4.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
20
|
+
carconnectivity_connector_seatcupra-0.2a4.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
|
21
|
+
carconnectivity_connector_seatcupra-0.2a4.dist-info/RECORD,,
|
@@ -24,13 +24,15 @@ from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive,
|
|
24
24
|
from carconnectivity.vehicle import GenericVehicle, ElectricVehicle
|
25
25
|
from carconnectivity.attributes import BooleanAttribute, DurationAttribute, GenericAttribute, TemperatureAttribute, EnumAttribute
|
26
26
|
from carconnectivity.units import Temperature
|
27
|
-
from carconnectivity.command_impl import ClimatizationStartStopCommand, WakeSleepCommand, HonkAndFlashCommand, LockUnlockCommand, ChargingStartStopCommand
|
27
|
+
from carconnectivity.command_impl import ClimatizationStartStopCommand, WakeSleepCommand, HonkAndFlashCommand, LockUnlockCommand, ChargingStartStopCommand, \
|
28
|
+
WindowHeatingStartStopCommand
|
28
29
|
from carconnectivity.climatization import Climatization
|
29
30
|
from carconnectivity.commands import Commands
|
30
31
|
from carconnectivity.charging import Charging
|
31
32
|
from carconnectivity.charging_connector import ChargingConnector
|
32
33
|
from carconnectivity.position import Position
|
33
34
|
from carconnectivity.enums import ConnectionState
|
35
|
+
from carconnectivity.window_heating import WindowHeatings
|
34
36
|
|
35
37
|
from carconnectivity_connectors.base.connector import BaseConnector
|
36
38
|
from carconnectivity_connectors.seatcupra.auth.session_manager import SessionManager, SessionUser, Service
|
@@ -423,7 +425,7 @@ class Connector(BaseConnector):
|
|
423
425
|
if vehicle.capabilities.has_capability('charging', check_status_ok=True):
|
424
426
|
if not isinstance(vehicle, SeatCupraElectricVehicle):
|
425
427
|
LOG.debug('Promoting %s to SeatCupraElectricVehicle object for %s', vehicle.__class__.__name__, vin)
|
426
|
-
vehicle = SeatCupraElectricVehicle(origin=vehicle)
|
428
|
+
vehicle = SeatCupraElectricVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
427
429
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
428
430
|
if not vehicle.charging.commands.contains_command('start-stop'):
|
429
431
|
charging_start_stop_command: ChargingStartStopCommand = ChargingStartStopCommand(parent=vehicle.charging.commands)
|
@@ -687,15 +689,15 @@ class Connector(BaseConnector):
|
|
687
689
|
has_combustion = True
|
688
690
|
if has_electric and not has_combustion and not isinstance(vehicle, SeatCupraElectricVehicle):
|
689
691
|
LOG.debug('Promoting %s to SeatCupraElectricVehicle object for %s', vehicle.__class__.__name__, vin)
|
690
|
-
vehicle = SeatCupraElectricVehicle(origin=vehicle)
|
692
|
+
vehicle = SeatCupraElectricVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
691
693
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
692
694
|
elif has_combustion and not has_electric and not isinstance(vehicle, SeatCupraCombustionVehicle):
|
693
695
|
LOG.debug('Promoting %s to SeatCupraCombustionVehicle object for %s', vehicle.__class__.__name__, vin)
|
694
|
-
vehicle = SeatCupraCombustionVehicle(origin=vehicle)
|
696
|
+
vehicle = SeatCupraCombustionVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
695
697
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
696
698
|
elif has_combustion and has_electric and not isinstance(vehicle, SeatCupraHybridVehicle):
|
697
699
|
LOG.debug('Promoting %s to SeatCupraHybridVehicle object for %s', vehicle.__class__.__name__, vin)
|
698
|
-
vehicle = SeatCupraHybridVehicle(origin=vehicle)
|
700
|
+
vehicle = SeatCupraHybridVehicle(garage=self.car_connectivity.garage, origin=vehicle)
|
699
701
|
self.car_connectivity.garage.replace_vehicle(vin, vehicle)
|
700
702
|
if 'services' in vehicle_status_data and vehicle_status_data['services'] is not None:
|
701
703
|
if 'charging' in vehicle_status_data['services'] and vehicle_status_data['services']['charging'] is not None:
|
@@ -958,7 +960,57 @@ class Connector(BaseConnector):
|
|
958
960
|
log_extra_keys(LOG_API, 'climatisationStatus', data['climatisationStatus'], {'carCapturedTimestamp', 'climatisationState'})
|
959
961
|
else:
|
960
962
|
vehicle.climatization.state._set_value(None) # pylint: disable=protected-access
|
961
|
-
|
963
|
+
if 'windowHeatingStatus' in data and data['windowHeatingStatus'] is not None:
|
964
|
+
window_heating_status: Dict = data['windowHeatingStatus']
|
965
|
+
if 'carCapturedTimestamp' not in window_heating_status or window_heating_status['carCapturedTimestamp'] is None:
|
966
|
+
raise APIError('Could not fetch vehicle status, carCapturedTimestamp missing')
|
967
|
+
captured_at: datetime = robust_time_parse(window_heating_status['carCapturedTimestamp'])
|
968
|
+
if 'windowHeatingStatus' in window_heating_status and window_heating_status['windowHeatingStatus'] is not None:
|
969
|
+
heating_on: bool = False
|
970
|
+
all_heating_invalid: bool = True
|
971
|
+
for window_heating in window_heating_status['windowHeatingStatus']:
|
972
|
+
if 'windowLocation' in window_heating and window_heating['windowLocation'] is not None:
|
973
|
+
window_id = window_heating['windowLocation']
|
974
|
+
if window_id in vehicle.window_heatings.windows:
|
975
|
+
window: WindowHeatings.WindowHeating = vehicle.window_heatings.windows[window_id]
|
976
|
+
else:
|
977
|
+
window = WindowHeatings.WindowHeating(window_id=window_id, window_heatings=vehicle.window_heatings)
|
978
|
+
vehicle.window_heatings.windows[window_id] = window
|
979
|
+
if 'windowHeatingState' in window_heating and window_heating['windowHeatingState'] is not None:
|
980
|
+
if window_heating['windowHeatingState'] in [item.value for item in WindowHeatings.HeatingState]:
|
981
|
+
window_heating_state: WindowHeatings.HeatingState = WindowHeatings.HeatingState(window_heating['windowHeatingState'])
|
982
|
+
if window_heating_state == WindowHeatings.HeatingState.ON:
|
983
|
+
heating_on = True
|
984
|
+
if window_heating_state in [WindowHeatings.HeatingState.ON,
|
985
|
+
WindowHeatings.HeatingState.OFF]:
|
986
|
+
all_heating_invalid = False
|
987
|
+
window.heating_state._set_value(window_heating_state, measured=captured_at) # pylint: disable=protected-access
|
988
|
+
else:
|
989
|
+
LOG_API.info('Unknown window heating state %s not in %s', window_heating['windowHeatingState'],
|
990
|
+
str(WindowHeatings.HeatingState))
|
991
|
+
# pylint: disable-next=protected-access
|
992
|
+
window.heating_state._set_value(WindowHeatings.HeatingState.UNKNOWN, measured=captured_at)
|
993
|
+
else:
|
994
|
+
window.heating_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
995
|
+
log_extra_keys(LOG_API, 'windowHeatingStatus', window_heating, {'windowLocation', 'windowHeatingState'})
|
996
|
+
if all_heating_invalid:
|
997
|
+
# pylint: disable-next=protected-access
|
998
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.INVALID, measured=captured_at)
|
999
|
+
else:
|
1000
|
+
if heating_on:
|
1001
|
+
# pylint: disable-next=protected-access
|
1002
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.ON, measured=captured_at)
|
1003
|
+
else:
|
1004
|
+
# pylint: disable-next=protected-access
|
1005
|
+
vehicle.window_heatings.heating_state._set_value(WindowHeatings.HeatingState.OFF, measured=captured_at)
|
1006
|
+
if vehicle.window_heatings is not None and vehicle.window_heatings.commands is not None \
|
1007
|
+
and not vehicle.window_heatings.commands.contains_command('start-stop'):
|
1008
|
+
start_stop_command = WindowHeatingStartStopCommand(parent=vehicle.window_heatings.commands)
|
1009
|
+
start_stop_command._add_on_set_hook(self.__on_window_heating_start_stop) # pylint: disable=protected-access
|
1010
|
+
start_stop_command.enabled = True
|
1011
|
+
vehicle.window_heatings.commands.add_command(start_stop_command)
|
1012
|
+
log_extra_keys(LOG_API, 'windowHeatingStatus', window_heating_status, {'carCapturedTimestamp', 'windowHeatingStatus'})
|
1013
|
+
log_extra_keys(LOG_API, 'climatisation', data, {'climatisationStatus', 'windowHeatingStatus'})
|
962
1014
|
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/vehicles/{vin}/climatisation/settings'
|
963
1015
|
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
964
1016
|
if data is not None:
|
@@ -1242,7 +1294,6 @@ class Connector(BaseConnector):
|
|
1242
1294
|
raise CommandError('VIN in object hierarchy missing')
|
1243
1295
|
if 'command' not in command_arguments:
|
1244
1296
|
raise CommandError('Command argument missing')
|
1245
|
-
command_dict: Dict = {}
|
1246
1297
|
try:
|
1247
1298
|
if command_arguments['command'] == ChargingStartStopCommand.Command.START:
|
1248
1299
|
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/start'
|
@@ -1531,10 +1582,12 @@ class Connector(BaseConnector):
|
|
1531
1582
|
if settings.target_temperature.enabled and settings.target_temperature.value is not None:
|
1532
1583
|
# Round target temperature to nearest 0.5
|
1533
1584
|
# Check if the attribute changed is the target_temperature attribute
|
1585
|
+
precision: float = settings.target_temperature.precision if settings.target_temperature.precision is not None else 0.5
|
1534
1586
|
if isinstance(attribute, TemperatureAttribute) and attribute.id == 'target_temperature':
|
1535
|
-
|
1587
|
+
value = round(value / settings.target_temperature.precision) * settings.target_temperature.precision
|
1588
|
+
setting_dict['targetTemperature'] = value
|
1536
1589
|
else:
|
1537
|
-
setting_dict['targetTemperature'] = round(settings.target_temperature.value
|
1590
|
+
setting_dict['targetTemperature'] = round(settings.target_temperature.value / precision) * precision
|
1538
1591
|
if settings.target_temperature.unit == Temperature.C:
|
1539
1592
|
setting_dict['targetTemperatureUnit'] = 'celsius'
|
1540
1593
|
elif settings.target_temperature.unit == Temperature.F:
|
@@ -1563,6 +1616,43 @@ class Connector(BaseConnector):
|
|
1563
1616
|
raise SetterError(f'Retrying failed: {retry_error}') from retry_error
|
1564
1617
|
return value
|
1565
1618
|
|
1619
|
+
def __on_window_heating_start_stop(self, start_stop_command: WindowHeatingStartStopCommand, command_arguments: Union[str, Dict[str, Any]]) \
|
1620
|
+
-> Union[str, Dict[str, Any]]:
|
1621
|
+
if start_stop_command.parent is None or start_stop_command.parent.parent is None \
|
1622
|
+
or start_stop_command.parent.parent.parent is None or not isinstance(start_stop_command.parent.parent.parent, SeatCupraVehicle):
|
1623
|
+
raise CommandError('Object hierarchy is not as expected')
|
1624
|
+
if not isinstance(command_arguments, dict):
|
1625
|
+
raise CommandError('Command arguments are not a dictionary')
|
1626
|
+
vehicle: SeatCupraVehicle = start_stop_command.parent.parent.parent
|
1627
|
+
vin: Optional[str] = vehicle.vin.value
|
1628
|
+
if vin is None:
|
1629
|
+
raise CommandError('VIN in object hierarchy missing')
|
1630
|
+
if 'command' not in command_arguments:
|
1631
|
+
raise CommandError('Command argument missing')
|
1632
|
+
try:
|
1633
|
+
if command_arguments['command'] == WindowHeatingStartStopCommand.Command.START:
|
1634
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/windowheating/requests/start'
|
1635
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
1636
|
+
elif command_arguments['command'] == WindowHeatingStartStopCommand.Command.STOP:
|
1637
|
+
url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/windowheating/requests/stop'
|
1638
|
+
command_response: requests.Response = self.session.post(url, allow_redirects=True)
|
1639
|
+
else:
|
1640
|
+
raise CommandError(f'Unknown command {command_arguments["command"]}')
|
1641
|
+
|
1642
|
+
if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
|
1643
|
+
LOG.error('Could not start/stop window heating (%s: %s)', command_response.status_code, command_response.text)
|
1644
|
+
raise CommandError(f'Could not start/stop window heating ({command_response.status_code}: {command_response.text})')
|
1645
|
+
except requests.exceptions.ConnectionError as connection_error:
|
1646
|
+
raise CommandError(f'Connection error: {connection_error}.'
|
1647
|
+
' If this happens frequently, please check if other applications communicate with the Seat/Cupra server.') from connection_error
|
1648
|
+
except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
|
1649
|
+
raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
|
1650
|
+
except requests.exceptions.ReadTimeout as timeout_error:
|
1651
|
+
raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
|
1652
|
+
except requests.exceptions.RetryError as retry_error:
|
1653
|
+
raise CommandError(f'Retrying failed: {retry_error}') from retry_error
|
1654
|
+
return command_arguments
|
1655
|
+
|
1566
1656
|
def get_version(self) -> str:
|
1567
1657
|
return __version__
|
1568
1658
|
|
@@ -34,7 +34,7 @@ class SeatCupraVehicle(GenericVehicle): # pylint: disable=too-many-instance-att
|
|
34
34
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
35
35
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
36
36
|
if origin is not None:
|
37
|
-
super().__init__(origin=origin)
|
37
|
+
super().__init__(garage=garage, origin=origin)
|
38
38
|
self.capabilities: Capabilities = origin.capabilities
|
39
39
|
self.capabilities.parent = self
|
40
40
|
if SUPPORT_IMAGES:
|
@@ -54,7 +54,7 @@ class SeatCupraElectricVehicle(ElectricVehicle, SeatCupraVehicle):
|
|
54
54
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
55
55
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
56
56
|
if origin is not None:
|
57
|
-
super().__init__(origin=origin)
|
57
|
+
super().__init__(garage=garage, origin=origin)
|
58
58
|
else:
|
59
59
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
60
60
|
|
@@ -66,7 +66,7 @@ class SeatCupraCombustionVehicle(CombustionVehicle, SeatCupraVehicle):
|
|
66
66
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
67
67
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
68
68
|
if origin is not None:
|
69
|
-
super().__init__(origin=origin)
|
69
|
+
super().__init__(garage=garage, origin=origin)
|
70
70
|
else:
|
71
71
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
72
72
|
|
@@ -78,6 +78,6 @@ class SeatCupraHybridVehicle(HybridVehicle, SeatCupraVehicle):
|
|
78
78
|
def __init__(self, vin: Optional[str] = None, garage: Optional[Garage] = None, managing_connector: Optional[BaseConnector] = None,
|
79
79
|
origin: Optional[SeatCupraVehicle] = None) -> None:
|
80
80
|
if origin is not None:
|
81
|
-
super().__init__(origin=origin)
|
81
|
+
super().__init__(garage=garage, origin=origin)
|
82
82
|
else:
|
83
83
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
File without changes
|
File without changes
|