carconnectivity-connector-seatcupra 0.1a6__py3-none-any.whl → 0.1a8__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.1a6
3
+ Version: 0.1a8
4
4
  Summary: CarConnectivity connector for Seat and Cupra services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -68,6 +68,7 @@ In your carconnectivity.json configuration add a section for the seatcupra conne
68
68
  {
69
69
  "type": "seatcupra",
70
70
  "config": {
71
+ "brand": "cupra",
71
72
  "username": "test@test.de",
72
73
  "password": "testpassword123"
73
74
  }
@@ -76,6 +77,8 @@ In your carconnectivity.json configuration add a section for the seatcupra conne
76
77
  }
77
78
  }
78
79
  ```
80
+ `brand` (`seat` or `cupra`) defines what login is used. MyCupra or MySeat account. Your credentials will work with both, but you may need to consent again to the terms and conditions when you use the "wrong" brand.
81
+
79
82
  ### Credentials
80
83
  If you do not want to provide your username or password inside the configuration you have to create a ".netrc" file at the appropriate location (usually this is your home folder):
81
84
  ```
@@ -1,21 +1,21 @@
1
1
  carconnectivity_connectors/seatcupra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- carconnectivity_connectors/seatcupra/_version.py,sha256=Hqe2m1dzf7-6SjKo8Gr6gXy8XAO0Guujh7xUPL78VzY,508
2
+ carconnectivity_connectors/seatcupra/_version.py,sha256=8cqHsmeL27BhXP-5TXDRomSBRkxC7CZnFEC8NypOGaI,508
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
6
  carconnectivity_connectors/seatcupra/command_impl.py,sha256=mtw8ZwJLmf79fPDZ1N3ImLfB8Gt9JPbzjMuIo2y5v3M,2879
7
- carconnectivity_connectors/seatcupra/connector.py,sha256=S6E7YlS8j39MPhV04ghOekevs53eEsZTlLyn7beeiMM,92982
7
+ carconnectivity_connectors/seatcupra/connector.py,sha256=MQ5zGNO051feTZUt23J-TJLQUKdOlzG3pYyeOVAGsaw,99318
8
8
  carconnectivity_connectors/seatcupra/vehicle.py,sha256=kiFVbJgq5VQOzf-vSli_2NsMgY0x4pwvJsjPWLGdr1g,3404
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
- carconnectivity_connectors/seatcupra/auth/my_cupra_session.py,sha256=iK5SlankZqaeneC3SNad8nHHcrP0tTmYxToI_9cqwlo,10744
11
+ carconnectivity_connectors/seatcupra/auth/my_cupra_session.py,sha256=ybBZ2y7-kUdo5MJ9Zin8UYViC0y3H43H3yOQcDGtWUo,12767
12
12
  carconnectivity_connectors/seatcupra/auth/openid_session.py,sha256=dA0vE2YuckkMPeqJo2dEI0h8_XfohdCgdGkTyshPF7Q,16858
13
- carconnectivity_connectors/seatcupra/auth/session_manager.py,sha256=NizIuY-pvkVBSwqYwFHKtjTU_02Nj4vMgjD_FjqCY6c,5377
14
- carconnectivity_connectors/seatcupra/auth/vw_web_session.py,sha256=hgsCdXugVnSgvLta4hBNtoNgMhAA83paAYO2fUOOFyM,10657
13
+ carconnectivity_connectors/seatcupra/auth/session_manager.py,sha256=ZIDvC848T3fy6PgGqCl8A2SzaNhu2YG19Xam5kgp7SA,5635
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.1a6.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
18
- carconnectivity_connector_seatcupra-0.1a6.dist-info/METADATA,sha256=gIbtmwE_VYMO2tDtu9jTTvXeNYAuBpyV3PUAdAt85W4,5386
19
- carconnectivity_connector_seatcupra-0.1a6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
20
- carconnectivity_connector_seatcupra-0.1a6.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
21
- carconnectivity_connector_seatcupra-0.1a6.dist-info/RECORD,,
17
+ carconnectivity_connector_seatcupra-0.1a8.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
18
+ carconnectivity_connector_seatcupra-0.1a8.dist-info/METADATA,sha256=OcY0IeJGVQIRGNGjdTUJ32jwKBA77KB_BNed0XxmTEg,5640
19
+ carconnectivity_connector_seatcupra-0.1a8.dist-info/WHEEL,sha256=nn6H5-ilmfVryoAQl3ZQ2l8SH5imPWFpm1A5FgEuFV4,91
20
+ carconnectivity_connector_seatcupra-0.1a8.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
21
+ carconnectivity_connector_seatcupra-0.1a8.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.1a6'
20
+ __version__ = version = '0.1a8'
21
21
  __version_tuple__ = version_tuple = (0, 1)
@@ -23,7 +23,7 @@ from carconnectivity_connectors.seatcupra.auth.openid_session import AccessType
23
23
  from carconnectivity_connectors.seatcupra.auth.vw_web_session import VWWebSession
24
24
 
25
25
  if TYPE_CHECKING:
26
- from typing import Tuple, Dict
26
+ from typing import Tuple, Dict, Any
27
27
 
28
28
 
29
29
  LOG: logging.Logger = logging.getLogger("carconnectivity.connectors.seatcupra.auth")
@@ -33,22 +33,40 @@ class MyCupraSession(VWWebSession):
33
33
  """
34
34
  MyCupraSession class handles the authentication and session management for Cupras's MyCupra service.
35
35
  """
36
- def __init__(self, session_user, **kwargs) -> None:
37
- super(MyCupraSession, self).__init__(client_id='3c756d46-f1ba-4d78-9f9a-cff0d5292d51@apps_vw-dilab_com',
38
- refresh_url='https://identity.vwgroup.io/oidc/v1/token',
39
- scope='openid profile nickname birthdate phone',
40
- redirect_uri='cupra://oauth-callback',
41
- state=None,
42
- session_user=session_user,
43
- **kwargs)
44
-
45
- self.headers = CaseInsensitiveDict({
46
- 'accept': '*/*',
47
- 'content-type': 'application/json',
48
- 'user-agent': 'CUPRAApp%20-%20Store/20220503 CFNetwork/1333.0.4 Darwin/21.5.0',
49
- 'accept-language': 'de-de',
50
- 'accept-encoding': 'gzip, deflate, br'
51
- })
36
+ def __init__(self, session_user, is_seat: bool, **kwargs) -> None:
37
+ self.is_seat: bool = is_seat
38
+ if self.is_seat:
39
+ super(MyCupraSession, self).__init__(client_id='99a5b77d-bd88-4d53-b4e5-a539c60694a3@apps_vw-dilab_com',
40
+ refresh_url='https://identity.vwgroup.io/oidc/v1/token',
41
+ scope='openid profile nickname birthdate phone',
42
+ redirect_uri='seat://oauth-callback',
43
+ state=None,
44
+ session_user=session_user,
45
+ **kwargs)
46
+
47
+ self.headers = CaseInsensitiveDict({
48
+ 'accept': '*/*',
49
+ 'content-type': 'application/json',
50
+ 'user-agent': 'SEATApp/2.5.0 (com.seat.myseat.ola; build:202410171614; iOS 15.8.3) Alamofire/5.7.0 Mobile',
51
+ 'accept-language': 'de-de',
52
+ 'accept-encoding': 'gzip, deflate, br'
53
+ })
54
+ else:
55
+ super(MyCupraSession, self).__init__(client_id='3c756d46-f1ba-4d78-9f9a-cff0d5292d51@apps_vw-dilab_com',
56
+ refresh_url='https://identity.vwgroup.io/oidc/v1/token',
57
+ scope='openid profile nickname birthdate phone',
58
+ redirect_uri='cupra://oauth-callback',
59
+ state=None,
60
+ session_user=session_user,
61
+ **kwargs)
62
+
63
+ self.headers = CaseInsensitiveDict({
64
+ 'accept': '*/*',
65
+ 'content-type': 'application/json',
66
+ 'user-agent': 'CUPRAApp%20-%20Store/20220503 CFNetwork/1333.0.4 Darwin/21.5.0',
67
+ 'accept-language': 'de-de',
68
+ 'accept-encoding': 'gzip, deflate, br'
69
+ })
52
70
 
53
71
  def login(self):
54
72
  super(MyCupraSession, self).login()
@@ -57,8 +75,12 @@ class MyCupraSession(VWWebSession):
57
75
  # perform web authentication
58
76
  response = self.do_web_auth(authorization_url_str)
59
77
  # fetch tokens from web authentication response
60
- self.fetch_tokens('https://identity.vwgroup.io/oidc/v1/token',
61
- authorization_response=response)
78
+ if self.is_seat:
79
+ return self.fetch_tokens('https://ola.prod.code.seat.cloud.vwgroup.com/authorization/api/v1/token',
80
+ authorization_response=response)
81
+ else:
82
+ self.fetch_tokens('https://identity.vwgroup.io/oidc/v1/token',
83
+ authorization_response=response)
62
84
 
63
85
  def refresh(self) -> None:
64
86
  # refresh tokens from refresh endpoint
@@ -92,15 +114,23 @@ class MyCupraSession(VWWebSession):
92
114
 
93
115
  if self.token is not None and all(key in self.token for key in ('state', 'id_token', 'access_token', 'code')):
94
116
  # Generate json body for token request
95
- body: Dict[str, str] = {
96
- 'state': self.token['state'],
97
- 'id_token': self.token['id_token'],
98
- 'redirect_uri': self.redirect_uri,
99
- 'client_id': self.client_id,
100
- 'client_secret': 'eb8814e641c81a2640ad62eeccec11c98effc9bccd4269ab7af338b50a94b3a2',
101
- 'code': self.token['code'],
102
- 'grant_type': 'authorization_code'
103
- }
117
+ if self.is_seat:
118
+ body: Dict[str, Any] = {'state': self.token['state'],
119
+ 'id_token': self.token['id_token'],
120
+ 'redirect_uri': self.redirect_uri,
121
+ 'client_id': self.client_id,
122
+ 'code': self.token['code'],
123
+ 'grant_type': 'authorization_code'
124
+ }
125
+ else:
126
+ body: Dict[str, Any] = {'state': self.token['state'],
127
+ 'id_token': self.token['id_token'],
128
+ 'redirect_uri': self.redirect_uri,
129
+ 'client_id': self.client_id,
130
+ 'client_secret': 'eb8814e641c81a2640ad62eeccec11c98effc9bccd4269ab7af338b50a94b3a2',
131
+ 'code': self.token['code'],
132
+ 'grant_type': 'authorization_code'
133
+ }
104
134
 
105
135
  request_headers: CaseInsensitiveDict = dict(self.headers) # pyright: ignore reportAssignmentType
106
136
  request_headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8'
@@ -47,11 +47,13 @@ class Service(Enum):
47
47
 
48
48
  Attributes:
49
49
  MY_CUPRA (str): Represents the 'MyCupra' service.
50
+ MY_SEAT (str): Represents the 'MySeat' service.
50
51
 
51
52
  Methods:
52
53
  __str__() -> str: Returns the string representation of the service.
53
54
  """
54
55
  MY_CUPRA = 'MyCupra'
56
+ MY_SEAT = 'MySeat'
55
57
 
56
58
  def __str__(self) -> str:
57
59
  return self.value
@@ -127,7 +129,9 @@ class SessionManager():
127
129
  cache = self.cache[identifier]
128
130
 
129
131
  if service == Service.MY_CUPRA:
130
- session = MyCupraSession(session_user=session_user, token=token, metadata=metadata, cache=cache)
132
+ session = MyCupraSession(session_user=session_user, is_seat=False, token=token, metadata=metadata, cache=cache)
133
+ elif service == Service.MY_SEAT:
134
+ session = MyCupraSession(session_user=session_user, is_seat=True, token=token, metadata=metadata, cache=cache)
131
135
  else:
132
136
  raise ValueError(f"Unsupported service: {service}")
133
137
 
@@ -121,6 +121,9 @@ class VWWebSession(OpenIDSession):
121
121
  raise RetrievalError('Temporary server error during login')
122
122
 
123
123
  if 'Location' not in response.headers:
124
+ if 'consent' in url:
125
+ raise AuthenticationError('Could not find Location in headers, probably due to missing consent. '
126
+ 'Check that you configured the correct brand or try visiting: ' + url)
124
127
  raise APICompatibilityError('Forwarding without Location in headers')
125
128
 
126
129
  url = response.headers['Location']
@@ -129,17 +129,30 @@ class Connector(BaseConnector):
129
129
  self.active_config['max_age'] = config['max_age']
130
130
  self.interval._set_value(timedelta(seconds=self.active_config['interval'])) # pylint: disable=protected-access
131
131
 
132
+ if 'brand' in config:
133
+ if config['brand'] not in ['seat', 'cupra']:
134
+ raise ValueError('Brand must be either "seat" or "cupra"')
135
+ self.active_config['brand'] = config['brand']
136
+ else:
137
+ self.active_config['brand'] = 'cupra'
138
+
132
139
  if self.active_config['username'] is None or self.active_config['password'] is None:
133
140
  raise AuthenticationError('Username or password not provided')
134
141
 
142
+ if self.active_config['brand'] == 'cupra':
143
+ service = Service.MY_CUPRA
144
+ elif self.active_config['brand'] == 'seat':
145
+ service = Service.MY_SEAT
146
+ else:
147
+ raise ValueError('Brand must be either "seat" or "cupra"')
135
148
  self._manager: SessionManager = SessionManager(tokenstore=car_connectivity.get_tokenstore(), cache=car_connectivity.get_cache())
136
- session: requests.Session = self._manager.get_session(Service.MY_CUPRA, SessionUser(username=self.active_config['username'],
137
- password=self.active_config['password']))
149
+ session: requests.Session = self._manager.get_session(service, SessionUser(username=self.active_config['username'],
150
+ password=self.active_config['password']))
138
151
  if not isinstance(session, MyCupraSession):
139
152
  raise AuthenticationError('Could not create session')
140
153
  self.session: MyCupraSession = session
141
154
  self.session.retries = 3
142
- self.session.timeout = 180
155
+ self.session.timeout = 30
143
156
  self.session.refresh()
144
157
 
145
158
  self._elapsed: List[timedelta] = []
@@ -1089,27 +1102,37 @@ class Connector(BaseConnector):
1089
1102
  if 'command' not in command_arguments:
1090
1103
  raise CommandError('Command argument missing')
1091
1104
  command_dict: Dict = {}
1092
- if command_arguments['command'] == ChargingStartStopCommand.Command.START:
1093
- url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/start'
1094
- if isinstance(vehicle, SeatCupraElectricVehicle) and vehicle.charging is not None and vehicle.charging.settings is not None \
1095
- and vehicle.charging.settings.maximum_current is not None and vehicle.charging.settings.maximum_current.enabled \
1096
- and vehicle.charging.settings.maximum_current.value is not None:
1097
- if vehicle.charging.settings.maximum_current.value <= 6:
1098
- command_dict['maxChargeCurrentAC'] = 'reduced'
1105
+ try:
1106
+ if command_arguments['command'] == ChargingStartStopCommand.Command.START:
1107
+ url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/start'
1108
+ if isinstance(vehicle, SeatCupraElectricVehicle) and vehicle.charging is not None and vehicle.charging.settings is not None \
1109
+ and vehicle.charging.settings.maximum_current is not None and vehicle.charging.settings.maximum_current.enabled \
1110
+ and vehicle.charging.settings.maximum_current.value is not None:
1111
+ if vehicle.charging.settings.maximum_current.value <= 6:
1112
+ command_dict['maxChargeCurrentAC'] = 'reduced'
1113
+ else:
1114
+ command_dict['maxChargeCurrentAC'] = 'maximum'
1099
1115
  else:
1100
1116
  command_dict['maxChargeCurrentAC'] = 'maximum'
1117
+ command_response: requests.Response = self.session.post(url, json=command_dict, allow_redirects=True)
1118
+ elif command_arguments['command'] == ChargingStartStopCommand.Command.STOP:
1119
+ url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/stop'
1120
+ command_response: requests.Response = self.session.post(url, data='{}', allow_redirects=True)
1101
1121
  else:
1102
- command_dict['maxChargeCurrentAC'] = 'maximum'
1103
- command_response: requests.Response = self.session.post(url, json=command_dict, allow_redirects=True)
1104
- elif command_arguments['command'] == ChargingStartStopCommand.Command.STOP:
1105
- url = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/charging/requests/stop'
1106
- command_response: requests.Response = self.session.post(url, data='{}', allow_redirects=True)
1107
- else:
1108
- raise CommandError(f'Unknown command {command_arguments["command"]}')
1109
-
1110
- if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1111
- LOG.error('Could not start/stop charging (%s: %s)', command_response.status_code, command_response.text)
1112
- raise CommandError(f'Could not start/stop charging ({command_response.status_code}: {command_response.text})')
1122
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1123
+
1124
+ if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1125
+ LOG.error('Could not start/stop charging (%s: %s)', command_response.status_code, command_response.text)
1126
+ raise CommandError(f'Could not start/stop charging ({command_response.status_code}: {command_response.text})')
1127
+ except requests.exceptions.ConnectionError as connection_error:
1128
+ raise CommandError(f'Connection error: {connection_error}.'
1129
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1130
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1131
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1132
+ except requests.exceptions.ReadTimeout as timeout_error:
1133
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1134
+ except requests.exceptions.RetryError as retry_error:
1135
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1113
1136
  return command_arguments
1114
1137
 
1115
1138
  def __on_air_conditioning_start_stop(self, start_stop_command: ClimatizationStartStopCommand, command_arguments: Union[str, Dict[str, Any]]) \
@@ -1155,10 +1178,20 @@ class Connector(BaseConnector):
1155
1178
  url: str = f'https://ola.prod.code.seat.cloud.vwgroup.com/vehicles/{vin}/climatisation/requests/stop'
1156
1179
  else:
1157
1180
  raise CommandError(f'Unknown command {command_arguments["command"]}')
1158
- command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1159
- if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1160
- LOG.error('Could not start/stop air conditioning (%s: %s)', command_response.status_code, command_response.text)
1161
- raise CommandError(f'Could not start/stop air conditioning ({command_response.status_code}: {command_response.text})')
1181
+ try:
1182
+ command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1183
+ if command_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1184
+ LOG.error('Could not start/stop air conditioning (%s: %s)', command_response.status_code, command_response.text)
1185
+ raise CommandError(f'Could not start/stop air conditioning ({command_response.status_code}: {command_response.text})')
1186
+ except requests.exceptions.ConnectionError as connection_error:
1187
+ raise CommandError(f'Connection error: {connection_error}.'
1188
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1189
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1190
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1191
+ except requests.exceptions.ReadTimeout as timeout_error:
1192
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1193
+ except requests.exceptions.RetryError as retry_error:
1194
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1162
1195
  return command_arguments
1163
1196
 
1164
1197
  def __on_spin(self, spin_command: SpinCommand, command_arguments: Union[str, Dict[str, Any]]) \
@@ -1181,12 +1214,22 @@ class Connector(BaseConnector):
1181
1214
  url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/users/{self.session.user_id}/spin/verify'
1182
1215
  else:
1183
1216
  raise CommandError(f'Unknown command {command_arguments["command"]}')
1184
- command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1185
- if command_response.status_code != requests.codes['ok']:
1186
- LOG.error('Could not execute spin command (%s: %s)', command_response.status_code, command_response.text)
1187
- raise CommandError(f'Could not execute spin command ({command_response.status_code}: {command_response.text})')
1188
- else:
1189
- LOG.info('Spin verify command executed successfully')
1217
+ try:
1218
+ command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1219
+ if command_response.status_code != requests.codes['ok']:
1220
+ LOG.error('Could not execute spin command (%s: %s)', command_response.status_code, command_response.text)
1221
+ raise CommandError(f'Could not execute spin command ({command_response.status_code}: {command_response.text})')
1222
+ else:
1223
+ LOG.info('Spin verify command executed successfully')
1224
+ except requests.exceptions.ConnectionError as connection_error:
1225
+ raise CommandError(f'Connection error: {connection_error}.'
1226
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1227
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1228
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1229
+ except requests.exceptions.ReadTimeout as timeout_error:
1230
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1231
+ except requests.exceptions.RetryError as retry_error:
1232
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1190
1233
  return command_arguments
1191
1234
 
1192
1235
  def __on_wake_sleep(self, wake_sleep_command: WakeSleepCommand, command_arguments: Union[str, Dict[str, Any]]) \
@@ -1205,10 +1248,20 @@ class Connector(BaseConnector):
1205
1248
  if command_arguments['command'] == WakeSleepCommand.Command.WAKE:
1206
1249
  url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/vehicle-wakeup/request'
1207
1250
 
1208
- command_response: requests.Response = self.session.post(url, data='{}', allow_redirects=True)
1209
- if command_response.status_code not in (requests.codes['ok'], requests.codes['no_content']):
1210
- LOG.error('Could not execute wake command (%s: %s)', command_response.status_code, command_response.text)
1211
- raise CommandError(f'Could not execute wake command ({command_response.status_code}: {command_response.text})')
1251
+ try:
1252
+ command_response: requests.Response = self.session.post(url, data='{}', allow_redirects=True)
1253
+ if command_response.status_code not in (requests.codes['ok'], requests.codes['no_content']):
1254
+ LOG.error('Could not execute wake command (%s: %s)', command_response.status_code, command_response.text)
1255
+ raise CommandError(f'Could not execute wake command ({command_response.status_code}: {command_response.text})')
1256
+ except requests.exceptions.ConnectionError as connection_error:
1257
+ raise CommandError(f'Connection error: {connection_error}.'
1258
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1259
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1260
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1261
+ except requests.exceptions.ReadTimeout as timeout_error:
1262
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1263
+ except requests.exceptions.RetryError as retry_error:
1264
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1212
1265
  elif command_arguments['command'] == WakeSleepCommand.Command.SLEEP:
1213
1266
  raise CommandError('Sleep command not supported by vehicle. Vehicle will put itself to sleep')
1214
1267
  else:
@@ -1244,12 +1297,22 @@ class Connector(BaseConnector):
1244
1297
  command_dict['userPosition']['longitude'] = vehicle.position.longitude.value
1245
1298
 
1246
1299
  url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/honk-and-flash'
1247
- command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1248
- if command_response.status_code not in (requests.codes['ok'], requests.codes['no_content']):
1249
- LOG.error('Could not execute honk or flash command (%s: %s)', command_response.status_code, command_response.text)
1250
- raise CommandError(f'Could not execute honk or flash command ({command_response.status_code}: {command_response.text})')
1251
- else:
1252
- raise CommandError(f'Unknown command {command_arguments["command"]}')
1300
+ try:
1301
+ command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1302
+ if command_response.status_code not in (requests.codes['ok'], requests.codes['no_content']):
1303
+ LOG.error('Could not execute honk or flash command (%s: %s)', command_response.status_code, command_response.text)
1304
+ raise CommandError(f'Could not execute honk or flash command ({command_response.status_code}: {command_response.text})')
1305
+ except requests.exceptions.ConnectionError as connection_error:
1306
+ raise CommandError(f'Connection error: {connection_error}.'
1307
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1308
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1309
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1310
+ except requests.exceptions.ReadTimeout as timeout_error:
1311
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1312
+ except requests.exceptions.RetryError as retry_error:
1313
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1314
+ else:
1315
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1253
1316
  return command_arguments
1254
1317
 
1255
1318
  def __on_lock_unlock(self, lock_unlock_command: LockUnlockCommand, command_arguments: Union[str, Dict[str, Any]]) \
@@ -1278,10 +1341,20 @@ class Connector(BaseConnector):
1278
1341
  url = f'https://ola.prod.code.seat.cloud.vwgroup.com/v1/vehicles/{vin}/access/unlock'
1279
1342
  else:
1280
1343
  raise CommandError(f'Unknown command {command_arguments["command"]}')
1281
- command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1282
- if command_response.status_code != requests.codes['ok']:
1283
- LOG.error('Could not execute locking command (%s: %s)', command_response.status_code, command_response.text)
1284
- raise CommandError(f'Could not execute locking command ({command_response.status_code}: {command_response.text})')
1344
+ try:
1345
+ command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1346
+ if command_response.status_code != requests.codes['ok']:
1347
+ LOG.error('Could not execute locking command (%s: %s)', command_response.status_code, command_response.text)
1348
+ raise CommandError(f'Could not execute locking command ({command_response.status_code}: {command_response.text})')
1349
+ except requests.exceptions.ConnectionError as connection_error:
1350
+ raise CommandError(f'Connection error: {connection_error}.'
1351
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1352
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1353
+ raise CommandError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1354
+ except requests.exceptions.ReadTimeout as timeout_error:
1355
+ raise CommandError(f'Timeout during read: {timeout_error}') from timeout_error
1356
+ except requests.exceptions.RetryError as retry_error:
1357
+ raise CommandError(f'Retrying failed: {retry_error}') from retry_error
1285
1358
  return command_arguments
1286
1359
 
1287
1360
  def __on_air_conditioning_settings_change(self, attribute: GenericAttribute, value: Any) -> Any:
@@ -1317,10 +1390,20 @@ class Connector(BaseConnector):
1317
1390
  setting_dict['climatisationWithoutExternalPower'] = settings.climatization_without_external_power.value
1318
1391
 
1319
1392
  url: str = f'https://ola.prod.code.seat.cloud.vwgroup.com/v2/vehicles/{vin}/climatisation/settings'
1320
- settings_response: requests.Response = self.session.post(url, data=json.dumps(setting_dict), allow_redirects=True)
1321
- if settings_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1322
- LOG.error('Could not set climatization settings (%s) %s', settings_response.status_code, settings_response.text)
1323
- raise SetterError(f'Could not set value ({settings_response.status_code}): {settings_response.text}')
1393
+ try:
1394
+ settings_response: requests.Response = self.session.post(url, data=json.dumps(setting_dict), allow_redirects=True)
1395
+ if settings_response.status_code not in [requests.codes['ok'], requests.codes['created']]:
1396
+ LOG.error('Could not set climatization settings (%s) %s', settings_response.status_code, settings_response.text)
1397
+ raise SetterError(f'Could not set value ({settings_response.status_code}): {settings_response.text}')
1398
+ except requests.exceptions.ConnectionError as connection_error:
1399
+ raise SetterError(f'Connection error: {connection_error}.'
1400
+ ' If this happens frequently, please check if other applications communicate with the Skoda server.') from connection_error
1401
+ except requests.exceptions.ChunkedEncodingError as chunked_encoding_error:
1402
+ raise SetterError(f'Error: {chunked_encoding_error}') from chunked_encoding_error
1403
+ except requests.exceptions.ReadTimeout as timeout_error:
1404
+ raise SetterError(f'Timeout during read: {timeout_error}') from timeout_error
1405
+ except requests.exceptions.RetryError as retry_error:
1406
+ raise SetterError(f'Retrying failed: {retry_error}') from retry_error
1324
1407
  return value
1325
1408
 
1326
1409
  def get_version(self) -> str: