carconnectivity-connector-seatcupra 0.1a7__tar.gz → 0.1a8__tar.gz

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.
Files changed (39) hide show
  1. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/PKG-INFO +4 -1
  2. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/README.md +3 -0
  3. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/doc/Config.md +1 -0
  4. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connector_seatcupra.egg-info/PKG-INFO +4 -1
  5. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/_version.py +1 -1
  6. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/my_cupra_session.py +58 -28
  7. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/session_manager.py +5 -1
  8. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/vw_web_session.py +3 -0
  9. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/connector.py +16 -3
  10. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.flake8 +0 -0
  11. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  12. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  13. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/dependabot.yml +0 -0
  14. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/workflows/build.yml +0 -0
  15. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/workflows/build_and_publish.yml +0 -0
  16. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.github/workflows/codeql-analysis.yml +0 -0
  17. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/.gitignore +0 -0
  18. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/CHANGELOG.md +0 -0
  19. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/LICENSE +0 -0
  20. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/Makefile +0 -0
  21. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/pyproject.toml +0 -0
  22. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/setup.cfg +0 -0
  23. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/setup_requirements.txt +0 -0
  24. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connector_seatcupra.egg-info/SOURCES.txt +0 -0
  25. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connector_seatcupra.egg-info/dependency_links.txt +0 -0
  26. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connector_seatcupra.egg-info/requires.txt +0 -0
  27. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connector_seatcupra.egg-info/top_level.txt +0 -0
  28. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/__init__.py +0 -0
  29. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/__init__.py +0 -0
  30. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/auth_util.py +0 -0
  31. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/helpers/blacklist_retry.py +0 -0
  32. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/auth/openid_session.py +0 -0
  33. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/capability.py +0 -0
  34. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/charging.py +0 -0
  35. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/climatization.py +0 -0
  36. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/command_impl.py +0 -0
  37. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/ui/connector_ui.py +0 -0
  38. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/src/carconnectivity_connectors/seatcupra/vehicle.py +0 -0
  39. {carconnectivity_connector_seatcupra-0.1a7 → carconnectivity_connector_seatcupra-0.1a8}/test/integration_test/carConnectivity.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-seatcupra
3
- Version: 0.1a7
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
  ```
@@ -24,6 +24,7 @@ In your carconnectivity.json configuration add a section for the seatcupra conne
24
24
  {
25
25
  "type": "seatcupra",
26
26
  "config": {
27
+ "brand": "cupra",
27
28
  "username": "test@test.de",
28
29
  "password": "testpassword123"
29
30
  }
@@ -32,6 +33,8 @@ In your carconnectivity.json configuration add a section for the seatcupra conne
32
33
  }
33
34
  }
34
35
  ```
36
+ `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.
37
+
35
38
  ### Credentials
36
39
  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):
37
40
  ```
@@ -13,6 +13,7 @@ These are the valid options for the Seat Cupra Connector
13
13
  "config": {
14
14
  "log_level": "error", // set the connectos log level
15
15
  "interval": 300, // Interval in which the server is checked in seconds
16
+ "brand": "seat", //Brand of the vehicle ("seat" or "cupra"), defines if MySeat or MyCupra account is used
16
17
  "username": "test@test.de", // Username of your Seat/Cupra Account
17
18
  "password": "testpassword123", // Username of your Seat/Cupra Account
18
19
  "spin": 1234, //S-Pin used for some special commands like locking/unlocking
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-seatcupra
3
- Version: 0.1a7
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
  ```
@@ -17,5 +17,5 @@ __version__: str
17
17
  __version_tuple__: VERSION_TUPLE
18
18
  version_tuple: VERSION_TUPLE
19
19
 
20
- __version__ = version = '0.1a7'
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] = []