carconnectivity-connector-skoda 0.8.1a2__py3-none-any.whl → 0.8.1a3__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.
Potentially problematic release.
This version of carconnectivity-connector-skoda might be problematic. Click here for more details.
- {carconnectivity_connector_skoda-0.8.1a2.dist-info → carconnectivity_connector_skoda-0.8.1a3.dist-info}/METADATA +4 -3
- {carconnectivity_connector_skoda-0.8.1a2.dist-info → carconnectivity_connector_skoda-0.8.1a3.dist-info}/RECORD +8 -8
- carconnectivity_connectors/skoda/_version.py +2 -2
- carconnectivity_connectors/skoda/auth/my_skoda_session.py +19 -13
- carconnectivity_connectors/skoda/mqtt_client.py +13 -3
- {carconnectivity_connector_skoda-0.8.1a2.dist-info → carconnectivity_connector_skoda-0.8.1a3.dist-info}/WHEEL +0 -0
- {carconnectivity_connector_skoda-0.8.1a2.dist-info → carconnectivity_connector_skoda-0.8.1a3.dist-info}/licenses/LICENSE +0 -0
- {carconnectivity_connector_skoda-0.8.1a2.dist-info → carconnectivity_connector_skoda-0.8.1a3.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carconnectivity-connector-skoda
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.1a3
|
|
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.
|
|
41
|
+
Requires-Dist: carconnectivity>=0.8.1
|
|
41
42
|
Requires-Dist: oauthlib~=3.3.1
|
|
42
|
-
Requires-Dist: requests~=2.32.
|
|
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
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
carconnectivity_connector_skoda-0.8.
|
|
1
|
+
carconnectivity_connector_skoda-0.8.1a3.dist-info/licenses/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
|
|
2
2
|
carconnectivity_connectors/skoda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
carconnectivity_connectors/skoda/_version.py,sha256=
|
|
3
|
+
carconnectivity_connectors/skoda/_version.py,sha256=EWYRAoLa3l60H6fP1alJLJWiiEVoVX2B_DgKklYl7ZA,712
|
|
4
4
|
carconnectivity_connectors/skoda/capability.py,sha256=TC8-yC23UUrf0faePdbZL0802DHXbtGDcSlt3vj5ltg,4770
|
|
5
5
|
carconnectivity_connectors/skoda/charging.py,sha256=7DPNiTWFhxiiEFKVnbIIU2TCmkpmcMWx_zsHXGXFpAQ,6856
|
|
6
6
|
carconnectivity_connectors/skoda/climatization.py,sha256=Jut468SkxjPBDTqroWFvDifVPfJBxGjsFed5pc4kZkg,1768
|
|
7
7
|
carconnectivity_connectors/skoda/command_impl.py,sha256=wDCI3Bka5pXlbyI4yVFS353TgFGyiBHBkERpP2g0A9w,3230
|
|
8
8
|
carconnectivity_connectors/skoda/connector.py,sha256=y25ZY1jCH-8IXSK847Stu4GbRK6j35xwZJKU9C7TSSU,147301
|
|
9
9
|
carconnectivity_connectors/skoda/error.py,sha256=ffxzvjmci7vtp9Q1K4DR1kBF0kTJxN5Gluci3kDBkEI,2459
|
|
10
|
-
carconnectivity_connectors/skoda/mqtt_client.py,sha256=
|
|
10
|
+
carconnectivity_connectors/skoda/mqtt_client.py,sha256=f4fRFeI1VUCGm9ZzGj_vnctiSIiMAoolYLAwKx4apqA,40086
|
|
11
11
|
carconnectivity_connectors/skoda/vehicle.py,sha256=q5gwe-_yPfE_-aEc17UQ-Q0Z46IN7PCpNG5jLw5PZl0,3981
|
|
12
12
|
carconnectivity_connectors/skoda/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
carconnectivity_connectors/skoda/auth/auth_util.py,sha256=dGLUbUre0HBsTg_Ii5vW34f8DLrCykYJYCyzEvUBBEE,4434
|
|
14
|
-
carconnectivity_connectors/skoda/auth/my_skoda_session.py,sha256=
|
|
14
|
+
carconnectivity_connectors/skoda/auth/my_skoda_session.py,sha256=j1iJc7qLQT4mOOML0NHLidj_WEE4gfTvHBZQTDjKd6o,10770
|
|
15
15
|
carconnectivity_connectors/skoda/auth/openid_session.py,sha256=Csn0kYxe_qo10ZHJlBtNV5kl6U4PTTxsC7FK-xfxGhY,17061
|
|
16
16
|
carconnectivity_connectors/skoda/auth/session_manager.py,sha256=Uf1vujuDBYUCAXhYToOsZkgbTtfmY3Qe0ICTfwomBpI,2899
|
|
17
17
|
carconnectivity_connectors/skoda/auth/skoda_web_session.py,sha256=tapjCRRPBu3tHrDoKmtuAlQhgxktib3oWTB8MHEzZTY,10816
|
|
18
18
|
carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
|
|
19
19
|
carconnectivity_connectors/skoda/ui/connector_ui.py,sha256=lLjwoakRaU0S80hAVwVi4JA1wtHycGHcoM2-7S9qsqI,1386
|
|
20
|
-
carconnectivity_connector_skoda-0.8.
|
|
21
|
-
carconnectivity_connector_skoda-0.8.
|
|
22
|
-
carconnectivity_connector_skoda-0.8.
|
|
23
|
-
carconnectivity_connector_skoda-0.8.
|
|
20
|
+
carconnectivity_connector_skoda-0.8.1a3.dist-info/METADATA,sha256=Xh4pdok2AmOaxHIbXq8moiEFHBMdGmsmSR8Zaqp1L5U,5436
|
|
21
|
+
carconnectivity_connector_skoda-0.8.1a3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
22
|
+
carconnectivity_connector_skoda-0.8.1a3.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
|
|
23
|
+
carconnectivity_connector_skoda-0.8.1a3.dist-info/RECORD,,
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.8.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 8, 1, '
|
|
31
|
+
__version__ = version = '0.8.1a3'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 8, 1, 'a3')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
|
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
|
|
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:
|
|
@@ -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
|
|
|
@@ -100,7 +100,12 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
100
100
|
del userdata
|
|
101
101
|
|
|
102
102
|
if self._skoda_connector.session.expired or self._skoda_connector.session.access_token is None:
|
|
103
|
-
|
|
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)
|
|
104
109
|
if not self._skoda_connector.session.expired and self._skoda_connector.session.access_token is not None:
|
|
105
110
|
# pylint: disable-next=attribute-defined-outside-init # this is a false positive, password has a setter in super class
|
|
106
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
|
|
@@ -344,7 +349,12 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
344
349
|
if self._retry_refresh_login_once == True:
|
|
345
350
|
self._retry_refresh_login_once = False
|
|
346
351
|
LOG.info('trying a relogin once to resolve the error')
|
|
347
|
-
|
|
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)
|
|
348
358
|
elif reason_code == 135:
|
|
349
359
|
LOG.error('Could not connect (%s): Not authorized', reason_code)
|
|
350
360
|
elif reason_code == 136:
|
|
File without changes
|
|
File without changes
|