carconnectivity-connector-skoda 0.7.1a1__tar.gz → 0.8.1__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.

Potentially problematic release.


This version of carconnectivity-connector-skoda might be problematic. Click here for more details.

Files changed (43) hide show
  1. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/workflows/build.yml +3 -3
  2. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/workflows/build_and_publish.yml +2 -2
  3. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/workflows/codeql-analysis.yml +4 -4
  4. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/CHANGELOG.md +35 -1
  5. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/PKG-INFO +5 -4
  6. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/pyproject.toml +4 -3
  7. carconnectivity_connector_skoda-0.8.1/setup_requirements.txt +6 -0
  8. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connector_skoda.egg-info/PKG-INFO +5 -4
  9. carconnectivity_connector_skoda-0.8.1/src/carconnectivity_connector_skoda.egg-info/requires.txt +5 -0
  10. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/_version.py +16 -3
  11. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/my_skoda_session.py +19 -13
  12. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/openid_session.py +5 -1
  13. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/capability.py +1 -1
  14. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/connector.py +17 -3
  15. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/mqtt_client.py +19 -2
  16. carconnectivity_connector_skoda-0.7.1a1/setup_requirements.txt +0 -6
  17. carconnectivity_connector_skoda-0.7.1a1/src/carconnectivity_connector_skoda.egg-info/requires.txt +0 -5
  18. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.flake8 +0 -0
  19. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  20. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  21. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.github/dependabot.yml +0 -0
  22. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/.gitignore +0 -0
  23. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/LICENSE +0 -0
  24. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/Makefile +0 -0
  25. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/README.md +0 -0
  26. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/doc/Config.md +0 -0
  27. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/setup.cfg +0 -0
  28. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connector_skoda.egg-info/SOURCES.txt +0 -0
  29. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connector_skoda.egg-info/dependency_links.txt +0 -0
  30. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connector_skoda.egg-info/top_level.txt +0 -0
  31. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/__init__.py +0 -0
  32. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/__init__.py +0 -0
  33. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/auth_util.py +0 -0
  34. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py +0 -0
  35. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/session_manager.py +0 -0
  36. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/auth/skoda_web_session.py +0 -0
  37. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/charging.py +0 -0
  38. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/climatization.py +0 -0
  39. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/command_impl.py +0 -0
  40. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/error.py +0 -0
  41. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/ui/connector_ui.py +0 -0
  42. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/src/carconnectivity_connectors/skoda/vehicle.py +0 -0
  43. {carconnectivity_connector_skoda-0.7.1a1 → carconnectivity_connector_skoda-0.8.1}/test/integration_test/carConnectivity.json +0 -0
@@ -22,12 +22,12 @@ jobs:
22
22
  runs-on: ubuntu-latest
23
23
  strategy:
24
24
  matrix:
25
- python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
25
+ python-version: ['3.10', '3.11', '3.12', '3.13', '3.14']
26
26
 
27
27
  steps:
28
- - uses: actions/checkout@v4
28
+ - uses: actions/checkout@v5
29
29
  - name: Set up Python ${{ matrix.python-version }}
30
- uses: actions/setup-python@v5
30
+ uses: actions/setup-python@v6
31
31
  with:
32
32
  python-version: ${{ matrix.python-version }}
33
33
  - name: Install dependencies
@@ -15,11 +15,11 @@ jobs:
15
15
  id-token: write
16
16
 
17
17
  steps:
18
- - uses: actions/checkout@v4
18
+ - uses: actions/checkout@v5
19
19
  with:
20
20
  fetch-depth: 0
21
21
  - name: Set up Python
22
- uses: actions/setup-python@v5
22
+ uses: actions/setup-python@v6
23
23
  with:
24
24
  python-version: "3.x"
25
25
  - name: Install dependencies
@@ -26,11 +26,11 @@ jobs:
26
26
 
27
27
  steps:
28
28
  - name: Checkout repository
29
- uses: actions/checkout@v4
29
+ uses: actions/checkout@v5
30
30
 
31
31
  # Initializes the CodeQL tools for scanning.
32
32
  - name: Initialize CodeQL
33
- uses: github/codeql-action/init@v3
33
+ uses: github/codeql-action/init@v4
34
34
  with:
35
35
  languages: ${{ matrix.language }}
36
36
  # If you wish to specify custom queries, you can do so here or in a config file.
@@ -41,7 +41,7 @@ jobs:
41
41
  # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
42
42
  # If this step fails, then you should remove it and run the build manually (see below)
43
43
  - name: Autobuild
44
- uses: github/codeql-action/autobuild@v3
44
+ uses: github/codeql-action/autobuild@v4
45
45
 
46
46
  # ℹ️ Command-line programs to run using the OS shell.
47
47
  # 📚 https://git.io/JvXDl
@@ -55,4 +55,4 @@ jobs:
55
55
  # make release
56
56
 
57
57
  - name: Perform CodeQL Analysis
58
- uses: github/codeql-action/analyze@v3
58
+ uses: github/codeql-action/analyze@v4
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
5
5
  ## [Unreleased]
6
6
  - No unreleased changes so far
7
7
 
8
+ ## [0.8.1] - 2025-11-02
9
+ ### Fixed
10
+ - Relogin when MQTT client receives a bad username or password error
11
+
12
+ ### Added
13
+ - Warning when connector detects suspicious token expiry
14
+
15
+ ### Changed
16
+ - Updated some dependencies
17
+
18
+ ## [0.8] - 2025-06-27
19
+ ### Added
20
+ - Support for adblue range
21
+
22
+ ## [0.7.3] - 2025-06-20
23
+ ### Fixed
24
+ - Fixes bug that registers hooks several times, causing multiple calls to the servers
25
+
26
+ ### Changed
27
+ - Updated dependencies
28
+
29
+ ## [0.7.2] - 2025-04-19
30
+ ### Fixed
31
+ - Fix for problems introduced with PyJWT
32
+
33
+ ## [0.7.1] - 2025-04-18
34
+ ### Fixed
35
+ - Fixed problem where driving range was not fetched when measurements capability had an expired license. Now it will be also fetched when charging license is active.
36
+
8
37
  ## [0.7] - 2025-04-17
9
38
  ### Fixed
10
39
  - Bug in mode attribute that caused the connector to crash
@@ -62,7 +91,12 @@ All notable changes to this project will be documented in this file.
62
91
  Initial release, let's go and give this to the public to try out...
63
92
  The API is not yet implemented completely but most functions already work
64
93
 
65
- [unreleased]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/compare/v0.7...HEAD
94
+ [unreleased]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/compare/v0.8.1...HEAD
95
+ [0.8.1]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.8.1
96
+ [0.8]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.8
97
+ [0.7.3]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.7.3
98
+ [0.7.2]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.7.2
99
+ [0.7.1]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.7.1
66
100
  [0.7]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.7
67
101
  [0.6]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.6
68
102
  [0.5]: https://github.com/tillsteinbach/CarConnectivity-connector-skoda/releases/tag/v0.5
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: carconnectivity-connector-skoda
3
- Version: 0.7.1a1
3
+ Version: 0.8.1
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -33,13 +33,14 @@ Classifier: Programming Language :: Python :: 3.10
33
33
  Classifier: Programming Language :: Python :: 3.11
34
34
  Classifier: Programming Language :: Python :: 3.12
35
35
  Classifier: Programming Language :: Python :: 3.13
36
+ Classifier: Programming Language :: Python :: 3.14
36
37
  Classifier: Topic :: Software Development :: Libraries
37
38
  Requires-Python: >=3.8
38
39
  Description-Content-Type: text/markdown
39
40
  License-File: LICENSE
40
- Requires-Dist: carconnectivity>=0.7
41
- Requires-Dist: oauthlib~=3.2.2
42
- Requires-Dist: requests~=2.32.3
41
+ Requires-Dist: carconnectivity>=0.8.1
42
+ Requires-Dist: oauthlib~=3.3.1
43
+ Requires-Dist: requests~=2.32.5
43
44
  Requires-Dist: pyjwt~=2.10
44
45
  Requires-Dist: paho-mqtt~=2.1.0
45
46
  Dynamic: license-file
@@ -14,9 +14,9 @@ authors = [
14
14
  { name = "Till Steinbach" }
15
15
  ]
16
16
  dependencies = [
17
- "carconnectivity>=0.7",
18
- "oauthlib~=3.2.2",
19
- "requests~=2.32.3",
17
+ "carconnectivity>=0.8.1",
18
+ "oauthlib~=3.3.1",
19
+ "requests~=2.32.5",
20
20
  "pyjwt~=2.10",
21
21
  "paho-mqtt~=2.1.0",
22
22
  ]
@@ -31,6 +31,7 @@ classifiers = [
31
31
  "Programming Language :: Python :: 3.11",
32
32
  "Programming Language :: Python :: 3.12",
33
33
  "Programming Language :: Python :: 3.13",
34
+ "Programming Language :: Python :: 3.14",
34
35
  "Topic :: Software Development :: Libraries"
35
36
  ]
36
37
 
@@ -0,0 +1,6 @@
1
+ flake8~=7.3.0
2
+ pylint~=4.0.2
3
+ bandit~=1.8.6
4
+
5
+ # For UI only
6
+ Flask~=3.1.2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: carconnectivity-connector-skoda
3
- Version: 0.7.1a1
3
+ Version: 0.8.1
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -33,13 +33,14 @@ Classifier: Programming Language :: Python :: 3.10
33
33
  Classifier: Programming Language :: Python :: 3.11
34
34
  Classifier: Programming Language :: Python :: 3.12
35
35
  Classifier: Programming Language :: Python :: 3.13
36
+ Classifier: Programming Language :: Python :: 3.14
36
37
  Classifier: Topic :: Software Development :: Libraries
37
38
  Requires-Python: >=3.8
38
39
  Description-Content-Type: text/markdown
39
40
  License-File: LICENSE
40
- Requires-Dist: carconnectivity>=0.7
41
- Requires-Dist: oauthlib~=3.2.2
42
- Requires-Dist: requests~=2.32.3
41
+ Requires-Dist: carconnectivity>=0.8.1
42
+ Requires-Dist: oauthlib~=3.3.1
43
+ Requires-Dist: requests~=2.32.5
43
44
  Requires-Dist: pyjwt~=2.10
44
45
  Requires-Dist: paho-mqtt~=2.1.0
45
46
  Dynamic: license-file
@@ -0,0 +1,5 @@
1
+ carconnectivity>=0.8.1
2
+ oauthlib~=3.3.1
3
+ requests~=2.32.5
4
+ pyjwt~=2.10
5
+ paho-mqtt~=2.1.0
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '0.7.1a1'
21
- __version_tuple__ = version_tuple = (0, 7, 1)
31
+ __version__ = version = '0.8.1'
32
+ __version_tuple__ = version_tuple = (0, 8, 1)
33
+
34
+ __commit_id__ = commit_id = 'g5123c7f6f'
@@ -15,6 +15,7 @@ from urllib.parse import parse_qsl, urlparse
15
15
 
16
16
  import requests
17
17
  from requests.models import CaseInsensitiveDict
18
+ from requests.exceptions import ReadTimeout, ConnectionError
18
19
 
19
20
  from oauthlib.common import add_params_to_uri, generate_nonce, to_unicode
20
21
  from oauthlib.oauth2 import InsecureTransportError
@@ -58,17 +59,22 @@ class MySkodaSession(SkodaWebSession):
58
59
  def login(self):
59
60
  super(MySkodaSession, self).login()
60
61
 
61
- verifier = "".join(random.choices(string.ascii_uppercase + string.digits, k=16))
62
- verifier_hash = hashlib.sha256(verifier.encode("utf-8")).digest()
63
- code_challenge = base64.b64encode(verifier_hash).decode("utf-8").replace("+", "-").replace("/", "_").rstrip("=")
64
- # retrieve authorization URL
65
- authorization_url = self.authorization_url(url='https://identity.vwgroup.io/oidc/v1/authorize', prompt='login', code_challenge=code_challenge,
66
- code_challenge_method='s256')
67
- # perform web authentication
68
- response = self.do_web_auth(authorization_url)
69
- # fetch tokens from web authentication response
70
- self.fetch_tokens('https://mysmob.api.connect.skoda-auto.cz/api/v1/authentication/exchange-authorization-code?tokenType=CONNECT',
71
- authorization_response=response, verifier=verifier)
62
+ try:
63
+ verifier = "".join(random.choices(string.ascii_uppercase + string.digits, k=16))
64
+ verifier_hash = hashlib.sha256(verifier.encode("utf-8")).digest()
65
+ code_challenge = base64.b64encode(verifier_hash).decode("utf-8").replace("+", "-").replace("/", "_").rstrip("=")
66
+ # retrieve authorization URL
67
+ authorization_url = self.authorization_url(url='https://identity.vwgroup.io/oidc/v1/authorize', prompt='login', code_challenge=code_challenge,
68
+ code_challenge_method='s256')
69
+ # perform web authentication
70
+ response = self.do_web_auth(authorization_url)
71
+ # fetch tokens from web authentication response
72
+ self.fetch_tokens('https://mysmob.api.connect.skoda-auto.cz/api/v1/authentication/exchange-authorization-code?tokenType=CONNECT',
73
+ authorization_response=response, verifier=verifier)
74
+ except ReadTimeout as exc:
75
+ raise TemporaryAuthenticationError('Login timed out (Read timeout)') from exc
76
+ except ConnectionError as exc:
77
+ raise TemporaryAuthenticationError('Login failed due to connection error') from exc
72
78
 
73
79
  def refresh(self) -> None:
74
80
  # refresh tokens from refresh endpoint
@@ -118,7 +124,7 @@ class MySkodaSession(SkodaWebSession):
118
124
  token_response = self.post(token_url, headers=request_headers, data=body, allow_redirects=False,
119
125
  access_type=AccessType.NONE) # pyright: ignore reportCallIssue
120
126
  if token_response.status_code != requests.codes['ok']:
121
- raise TemporaryAuthenticationError(f'Token could not be fetched due to temporary WeConnect failure: {token_response.status_code}')
127
+ raise TemporaryAuthenticationError(f'Token could not be fetched due to temporary MySkoda failure: {token_response.status_code}')
122
128
  # parse token from response body
123
129
  token = self.parse_from_body(token_response.text)
124
130
  return token
@@ -132,7 +138,7 @@ class MySkodaSession(SkodaWebSession):
132
138
  # Tokens are in body of response in json format
133
139
  token = json.loads(token_response)
134
140
  except json.decoder.JSONDecodeError as err:
135
- raise TemporaryAuthenticationError('Token could not be refreshed due to temporary WeConnect failure: json could not be decoded') from err
141
+ raise TemporaryAuthenticationError('Token could not be refreshed due to temporary MySkoda failure: json could not be decoded') from err
136
142
  found_tokens: Set[str] = set()
137
143
  # Fix token keys, we want access_token instead of accessToken
138
144
  if 'accessToken' in token:
@@ -153,7 +153,7 @@ class OpenIDSession(requests.Session):
153
153
  new_token['expires_in'] = self._token['expires_in']
154
154
  else:
155
155
  if 'id_token' in new_token:
156
- meta_data = jwt.decode(new_token['id_token'], do_verify=False)
156
+ meta_data = jwt.decode(new_token['id_token'], options={"verify_signature": False})
157
157
  if 'exp' in meta_data:
158
158
  new_token['expires_at'] = meta_data['exp']
159
159
  expires_at = datetime.fromtimestamp(meta_data['exp'], tz=timezone.utc)
@@ -165,6 +165,10 @@ class OpenIDSession(requests.Session):
165
165
  # If expires_in is set and expires_at is not set we calculate expires_at from expires_in using the current time
166
166
  if 'expires_in' in new_token and 'expires_at' not in new_token:
167
167
  new_token['expires_at'] = time.time() + int(new_token.get('expires_in'))
168
+ if new_token['expires_in'] > 3600:
169
+ LOG.warning('unexpected Token expires_in > 3600s (%d)', new_token['expires_in'])
170
+ if new_token['expires_at'] > (time.time() + 3600):
171
+ LOG.warning('unexpected Token expires_at after more than 3600s')
168
172
  self._token = new_token
169
173
 
170
174
  @property
@@ -132,7 +132,7 @@ class Capability(GenericObject):
132
132
  LOCATION_DATA_DISABLED = 1013
133
133
  LICENSE_INACTIVE = 2001
134
134
  LICENSE_EXPIRED = 2002
135
- MISSING_LICENSE = 2003
135
+ LICENSE_MISSING = 2003
136
136
  USER_NOT_VERIFIED = 3001
137
137
  TERMS_AND_CONDITIONS_NOT_ACCEPTED = 3002
138
138
  INSUFFICIENT_RIGHTS = 3003
@@ -22,7 +22,7 @@ from carconnectivity.units import Length, Speed, Power, Temperature
22
22
  from carconnectivity.doors import Doors
23
23
  from carconnectivity.windows import Windows
24
24
  from carconnectivity.lights import Lights
25
- from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive
25
+ from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive, DieselDrive
26
26
  from carconnectivity.attributes import BooleanAttribute, DurationAttribute, TemperatureAttribute, EnumAttribute, LevelAttribute, \
27
27
  CurrentAttribute
28
28
  from carconnectivity.charging import Charging
@@ -407,7 +407,7 @@ class Connector(BaseConnector):
407
407
  if vehicle is not None:
408
408
  if vehicle.connection_state is not None and vehicle.connection_state.enabled \
409
409
  and vehicle.connection_state.value == GenericVehicle.ConnectionState.OFFLINE:
410
- vehicle.state._set_value(GenericVehicle.State.OFFLINE)
410
+ vehicle.state._set_value(GenericVehicle.State.OFFLINE) # pylint: disable=protected-access
411
411
  elif vehicle.in_motion is not None and vehicle.in_motion.enabled and vehicle.in_motion.value:
412
412
  vehicle.state._set_value(GenericVehicle.State.IGNITION_ON) # pylint: disable=protected-access
413
413
  elif vehicle.position is not None and vehicle.position.enabled and vehicle.position.position_type is not None \
@@ -1301,10 +1301,11 @@ class Connector(BaseConnector):
1301
1301
  else:
1302
1302
  if engine_type == GenericDrive.Type.ELECTRIC:
1303
1303
  drive = ElectricDrive(drive_id=drive_id, drives=vehicle.drives)
1304
+ elif engine_type == GenericDrive.Type.DIESEL:
1305
+ drive = DieselDrive(drive_id=drive_id, drives=vehicle.drives)
1304
1306
  elif engine_type in [GenericDrive.Type.FUEL,
1305
1307
  GenericDrive.Type.GASOLINE,
1306
1308
  GenericDrive.Type.PETROL,
1307
- GenericDrive.Type.DIESEL,
1308
1309
  GenericDrive.Type.CNG,
1309
1310
  GenericDrive.Type.LPG]:
1310
1311
  drive = CombustionDrive(drive_id=drive_id, drives=vehicle.drives)
@@ -1335,9 +1336,22 @@ class Connector(BaseConnector):
1335
1336
  'currentSoCInPercent',
1336
1337
  'currentFuelLevelInPercent',
1337
1338
  'remainingRangeInKm'})
1339
+ if 'adBlueRange' in range_data and range_data['adBlueRange'] is not None:
1340
+ # pylint: disable-next=protected-access
1341
+ for drive in vehicle.drives.drives.values():
1342
+ if isinstance(drive, DieselDrive):
1343
+ # pylint: disable-next=protected-access
1344
+ drive.adblue_range._set_value(value=range_data['adBlueRange'], measured=captured_at, unit=Length.KM)
1345
+ drive.adblue_range.precision = 1
1346
+ else:
1347
+ for drive in vehicle.drives.drives.values():
1348
+ if isinstance(drive, DieselDrive):
1349
+ # pylint: disable-next=protected-access
1350
+ drive.adblue_range._set_value(value=None, measured=captured_at, unit=Length.KM)
1338
1351
  log_extra_keys(LOG_API, '/api/v2/vehicle-status/{vin}/driving-range', range_data, {'carCapturedTimestamp',
1339
1352
  'carType',
1340
1353
  'totalRangeInKm',
1354
+ 'adBlueRange',
1341
1355
  'primaryEngineRange',
1342
1356
  'secondaryEngineRange'})
1343
1357
  return vehicle
@@ -13,7 +13,7 @@ from datetime import timedelta, timezone
13
13
  from paho.mqtt.client import Client
14
14
  from paho.mqtt.enums import MQTTProtocolVersion, CallbackAPIVersion, MQTTErrorCode
15
15
 
16
- from carconnectivity.errors import CarConnectivityError
16
+ from carconnectivity.errors import CarConnectivityError, TemporaryAuthenticationError
17
17
  from carconnectivity.observable import Observable
18
18
  from carconnectivity.vehicle import GenericVehicle
19
19
 
@@ -70,6 +70,8 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
70
70
  self.delayed_access_function_timers: Dict[str, threading.Timer] = {}
71
71
 
72
72
  self.tls_set(cert_reqs=ssl.CERT_NONE)
73
+
74
+ self._retry_refresh_login_once = True
73
75
 
74
76
  def connect(self, *args, **kwargs) -> MQTTErrorCode:
75
77
  """
@@ -98,7 +100,12 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
98
100
  del userdata
99
101
 
100
102
  if self._skoda_connector.session.expired or self._skoda_connector.session.access_token is None:
101
- self._skoda_connector.session.refresh()
103
+ try:
104
+ self._skoda_connector.session.refresh()
105
+ except ConnectionError as exc:
106
+ LOG.error('Token refresh failed due to connection error: %s', exc)
107
+ except TemporaryAuthenticationError as exc:
108
+ LOG.error('Token refresh failed due to temporary MySkoda error: %s', exc)
102
109
  if not self._skoda_connector.session.expired and self._skoda_connector.session.access_token is not None:
103
110
  # pylint: disable-next=attribute-defined-outside-init # this is a false positive, password has a setter in super class
104
111
  self._password = self._skoda_connector.session.access_token # This is a bit hacky but if password attribute is used here there is an Exception
@@ -321,6 +328,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
321
328
  self._skoda_connector.car_connectivity.garage.add_observer(observer=self._on_carconnectivity_vehicle_enabled,
322
329
  flag=observer_flags,
323
330
  priority=Observable.ObserverPriority.USER_MID)
331
+ self._retry_refresh_login_once = True
324
332
  self._subscribe_vehicles()
325
333
 
326
334
  # Handle different reason codes
@@ -338,6 +346,15 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
338
346
  LOG.error('Could not connect (%s): Client identifier not valid', reason_code)
339
347
  elif reason_code == 134:
340
348
  LOG.error('Could not connect (%s): Bad user name or password', reason_code)
349
+ if self._retry_refresh_login_once == True:
350
+ self._retry_refresh_login_once = False
351
+ LOG.info('trying a relogin once to resolve the error')
352
+ try:
353
+ self._skoda_connector.session.login()
354
+ except TemporaryAuthenticationError as exc:
355
+ LOG.error('Login failed due to temporary MySkoda error: %s', exc)
356
+ except ConnectionError as exc:
357
+ LOG.error('Login failed due to connection error: %s', exc)
341
358
  elif reason_code == 135:
342
359
  LOG.error('Could not connect (%s): Not authorized', reason_code)
343
360
  elif reason_code == 136:
@@ -1,6 +0,0 @@
1
- flake8~=7.2.0
2
- pylint~=3.3.6
3
- bandit~=1.8.3
4
-
5
- # For UI only
6
- Flask~=3.1.0
@@ -1,5 +0,0 @@
1
- carconnectivity>=0.7
2
- oauthlib~=3.2.2
3
- requests~=2.32.3
4
- pyjwt~=2.10
5
- paho-mqtt~=2.1.0