carconnectivity-connector-skoda 0.1a10__py3-none-any.whl → 0.1a11__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_skoda-0.1a10.dist-info → carconnectivity_connector_skoda-0.1a11.dist-info}/METADATA +1 -1
- {carconnectivity_connector_skoda-0.1a10.dist-info → carconnectivity_connector_skoda-0.1a11.dist-info}/RECORD +8 -8
- carconnectivity_connectors/skoda/_version.py +1 -1
- carconnectivity_connectors/skoda/connector.py +15 -14
- carconnectivity_connectors/skoda/mqtt_client.py +53 -4
- {carconnectivity_connector_skoda-0.1a10.dist-info → carconnectivity_connector_skoda-0.1a11.dist-info}/LICENSE +0 -0
- {carconnectivity_connector_skoda-0.1a10.dist-info → carconnectivity_connector_skoda-0.1a11.dist-info}/WHEEL +0 -0
- {carconnectivity_connector_skoda-0.1a10.dist-info → carconnectivity_connector_skoda-0.1a11.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
carconnectivity_connectors/skoda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
carconnectivity_connectors/skoda/_version.py,sha256
|
|
2
|
+
carconnectivity_connectors/skoda/_version.py,sha256=lXj09wNlQE2ygonVVc_Fk2FN_1_4nx6sHnElAwbvzHM,409
|
|
3
3
|
carconnectivity_connectors/skoda/capability.py,sha256=JlNEaisVYF8qWv0wNDHTaas36uIpTIQ3NVR69wesiYQ,4513
|
|
4
4
|
carconnectivity_connectors/skoda/charging.py,sha256=oDHxZxrfTMvtYCJxmGfKFeWVMH4ceQ5HTKRAspnsunU,3312
|
|
5
|
-
carconnectivity_connectors/skoda/connector.py,sha256=
|
|
6
|
-
carconnectivity_connectors/skoda/mqtt_client.py,sha256=
|
|
5
|
+
carconnectivity_connectors/skoda/connector.py,sha256=xiPPT6XTVWsLvu0iqZvSPpgtHm3DrR1TKUL4d4NRz2Y,62158
|
|
6
|
+
carconnectivity_connectors/skoda/mqtt_client.py,sha256=ZB56Za1k5vbxQPl5qCvukE46Tq1O0-Cn19kBz_bDJZM,31782
|
|
7
7
|
carconnectivity_connectors/skoda/vehicle.py,sha256=H3GRDNimMghFwFi--y9BsgoSK3pMibNf_l6SsDN6gvQ,2759
|
|
8
8
|
carconnectivity_connectors/skoda/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
carconnectivity_connectors/skoda/auth/auth_util.py,sha256=dGLUbUre0HBsTg_Ii5vW34f8DLrCykYJYCyzEvUBBEE,4434
|
|
@@ -12,8 +12,8 @@ carconnectivity_connectors/skoda/auth/openid_session.py,sha256=LusWi2FZZIL3buodG
|
|
|
12
12
|
carconnectivity_connectors/skoda/auth/session_manager.py,sha256=Uf1vujuDBYUCAXhYToOsZkgbTtfmY3Qe0ICTfwomBpI,2899
|
|
13
13
|
carconnectivity_connectors/skoda/auth/skoda_web_session.py,sha256=cjzMkzx473Sh-4RgZAQULeRRcxB1MboddldCVM_y5LE,10640
|
|
14
14
|
carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
|
|
15
|
-
carconnectivity_connector_skoda-0.
|
|
16
|
-
carconnectivity_connector_skoda-0.
|
|
17
|
-
carconnectivity_connector_skoda-0.
|
|
18
|
-
carconnectivity_connector_skoda-0.
|
|
19
|
-
carconnectivity_connector_skoda-0.
|
|
15
|
+
carconnectivity_connector_skoda-0.1a11.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
|
|
16
|
+
carconnectivity_connector_skoda-0.1a11.dist-info/METADATA,sha256=tS2ccqTBaAHPxFbNRA7wlbJQPiqLDU8J9h62FQcXvb8,5327
|
|
17
|
+
carconnectivity_connector_skoda-0.1a11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
18
|
+
carconnectivity_connector_skoda-0.1a11.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
|
|
19
|
+
carconnectivity_connector_skoda-0.1a11.dist-info/RECORD,,
|
|
@@ -312,7 +312,7 @@ class Connector(BaseConnector):
|
|
|
312
312
|
if vehicle_to_update.capabilities.has_capability('AIR_CONDITIONING'):
|
|
313
313
|
vehicle_to_update = self.fetch_air_conditioning(vehicle_to_update)
|
|
314
314
|
|
|
315
|
-
def fetch_charging(self, vehicle: SkodaElectricVehicle) -> SkodaElectricVehicle:
|
|
315
|
+
def fetch_charging(self, vehicle: SkodaElectricVehicle, no_cache: bool = False) -> SkodaElectricVehicle:
|
|
316
316
|
"""
|
|
317
317
|
Fetches the charging information for a given Skoda electric vehicle.
|
|
318
318
|
|
|
@@ -329,7 +329,7 @@ class Connector(BaseConnector):
|
|
|
329
329
|
if vehicle.charging is None:
|
|
330
330
|
raise ValueError('Vehicle has no charging object')
|
|
331
331
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}'
|
|
332
|
-
data: Dict[str, Any] | None = self._fetch_data(url, session=self.session)
|
|
332
|
+
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
333
333
|
if data is not None:
|
|
334
334
|
if 'carCapturedTimestamp' in data and data['carCapturedTimestamp'] is not None:
|
|
335
335
|
captured_at: datetime = robust_time_parse(data['carCapturedTimestamp'])
|
|
@@ -372,7 +372,7 @@ class Connector(BaseConnector):
|
|
|
372
372
|
log_extra_keys(LOG_API, 'charging data', data, {'carCapturedTimestamp', 'status'})
|
|
373
373
|
return vehicle
|
|
374
374
|
|
|
375
|
-
def fetch_position(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
375
|
+
def fetch_position(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
376
376
|
"""
|
|
377
377
|
Fetches the position of the given Skoda vehicle and updates its position attributes.
|
|
378
378
|
|
|
@@ -392,7 +392,7 @@ class Connector(BaseConnector):
|
|
|
392
392
|
if vehicle.position is None:
|
|
393
393
|
raise ValueError('Vehicle has no charging object')
|
|
394
394
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/maps/positions?vin={vin}'
|
|
395
|
-
data: Dict[str, Any] | None = self._fetch_data(url, session=self.session)
|
|
395
|
+
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
396
396
|
if data is not None:
|
|
397
397
|
if 'positions' in data and data['positions'] is not None:
|
|
398
398
|
for position_dict in data['positions']:
|
|
@@ -426,7 +426,7 @@ class Connector(BaseConnector):
|
|
|
426
426
|
vehicle.position.position_type._set_value(None) # pylint: disable=protected-access
|
|
427
427
|
return vehicle
|
|
428
428
|
|
|
429
|
-
def fetch_air_conditioning(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
429
|
+
def fetch_air_conditioning(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
430
430
|
"""
|
|
431
431
|
Fetches the air conditioning data for a given Skoda vehicle and updates the vehicle object with the retrieved data.
|
|
432
432
|
|
|
@@ -451,7 +451,7 @@ class Connector(BaseConnector):
|
|
|
451
451
|
if vehicle.position is None:
|
|
452
452
|
raise ValueError('Vehicle has no charging object')
|
|
453
453
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/air-conditioning/{vin}'
|
|
454
|
-
data: Dict[str, Any] | None = self._fetch_data(url, session=self.session)
|
|
454
|
+
data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
455
455
|
if data is not None:
|
|
456
456
|
if 'carCapturedTimestamp' in data and data['carCapturedTimestamp'] is not None:
|
|
457
457
|
captured_at: datetime = robust_time_parse(data['carCapturedTimestamp'])
|
|
@@ -529,7 +529,7 @@ class Connector(BaseConnector):
|
|
|
529
529
|
'targetTemperature', 'outsideTemperature'})
|
|
530
530
|
return vehicle
|
|
531
531
|
|
|
532
|
-
def fetch_vehicle_details(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
532
|
+
def fetch_vehicle_details(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
533
533
|
"""
|
|
534
534
|
Fetches the details of a vehicle from the Skoda API.
|
|
535
535
|
|
|
@@ -544,7 +544,7 @@ class Connector(BaseConnector):
|
|
|
544
544
|
raise APIError('VIN is missing')
|
|
545
545
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/garage/vehicles/{vin}?' \
|
|
546
546
|
'connectivityGenerations=MOD1&connectivityGenerations=MOD2&connectivityGenerations=MOD3&connectivityGenerations=MOD4'
|
|
547
|
-
vehicle_data: Dict[str, Any] | None = self._fetch_data(url, self.session)
|
|
547
|
+
vehicle_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
548
548
|
if vehicle_data:
|
|
549
549
|
if 'softwareVersion' in vehicle_data and vehicle_data['softwareVersion'] is not None:
|
|
550
550
|
vehicle.software.version._set_value(vehicle_data['softwareVersion']) # pylint: disable=protected-access
|
|
@@ -582,7 +582,7 @@ class Connector(BaseConnector):
|
|
|
582
582
|
log_extra_keys(LOG_API, 'api/v2/garage/vehicles/VIN', vehicle_data, {'softwareVersion'})
|
|
583
583
|
return vehicle
|
|
584
584
|
|
|
585
|
-
def fetch_driving_range(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
585
|
+
def fetch_driving_range(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
586
586
|
"""
|
|
587
587
|
Fetches the driving range data for a given Skoda vehicle and updates the vehicle object accordingly.
|
|
588
588
|
|
|
@@ -605,7 +605,7 @@ class Connector(BaseConnector):
|
|
|
605
605
|
if vin is None:
|
|
606
606
|
raise APIError('VIN is missing')
|
|
607
607
|
url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}/driving-range'
|
|
608
|
-
range_data: Dict[str, Any] | None = self._fetch_data(url, self.session)
|
|
608
|
+
range_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
609
609
|
if range_data:
|
|
610
610
|
captured_at: datetime = robust_time_parse(range_data['carCapturedTimestamp'])
|
|
611
611
|
# Check vehicle type and if it does not match the current vehicle type, create a new vehicle object using copy constructor
|
|
@@ -692,7 +692,7 @@ class Connector(BaseConnector):
|
|
|
692
692
|
'secondaryEngineRange'})
|
|
693
693
|
return vehicle
|
|
694
694
|
|
|
695
|
-
def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle) -> SkodaVehicle:
|
|
695
|
+
def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
696
696
|
"""
|
|
697
697
|
Fetches the status of a vehicle from other Skoda API.
|
|
698
698
|
|
|
@@ -706,7 +706,7 @@ class Connector(BaseConnector):
|
|
|
706
706
|
if vin is None:
|
|
707
707
|
raise APIError('VIN is missing')
|
|
708
708
|
url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
|
|
709
|
-
vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url, self.session)
|
|
709
|
+
vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
|
|
710
710
|
if vehicle_status_data:
|
|
711
711
|
if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
|
|
712
712
|
vehicle_status_data = vehicle_status_data['remote']
|
|
@@ -881,10 +881,11 @@ class Connector(BaseConnector):
|
|
|
881
881
|
"""
|
|
882
882
|
self._elapsed.append(elapsed)
|
|
883
883
|
|
|
884
|
-
def _fetch_data(self, url, session,
|
|
884
|
+
def _fetch_data(self, url, session, no_cache=False, allow_empty=False, allow_http_error=False,
|
|
885
|
+
allowed_errors=None) -> Optional[Dict[str, Any]]: # noqa: C901
|
|
885
886
|
data: Optional[Dict[str, Any]] = None
|
|
886
887
|
cache_date: Optional[datetime] = None
|
|
887
|
-
if not
|
|
888
|
+
if not no_cache and (self.max_age is not None and session.cache is not None and url in session.cache):
|
|
888
889
|
data, cache_date_string = session.cache[url]
|
|
889
890
|
cache_date = datetime.fromisoformat(cache_date_string)
|
|
890
891
|
if data is None or self.max_age is None \
|
|
@@ -7,6 +7,7 @@ import logging
|
|
|
7
7
|
import uuid
|
|
8
8
|
import ssl
|
|
9
9
|
import json
|
|
10
|
+
import threading
|
|
10
11
|
from datetime import timedelta, timezone
|
|
11
12
|
|
|
12
13
|
from paho.mqtt.client import Client
|
|
@@ -57,6 +58,8 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
57
58
|
self.on_subscribe = self._on_subscribe_callback
|
|
58
59
|
self.subscribed_topics: Set[str] = set()
|
|
59
60
|
|
|
61
|
+
self.delayed_access_function_timers: Dict[str, threading.Timer] = {}
|
|
62
|
+
|
|
60
63
|
self.tls_set(cert_reqs=ssl.CERT_NONE)
|
|
61
64
|
|
|
62
65
|
def connect(self, *args, **kwargs) -> MQTTErrorCode:
|
|
@@ -437,7 +440,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
437
440
|
return
|
|
438
441
|
|
|
439
442
|
# service_events
|
|
440
|
-
match = re.match(r'^(?P<user_id>[0-9a-fA-F-]+)/(?P<vin>[A-Z0-9]+)/service-event/(?P<service_event>[a-zA-Z0-9-_]+)$', msg.topic)
|
|
443
|
+
match = re.match(r'^(?P<user_id>[0-9a-fA-F-]+)/(?P<vin>[A-Z0-9]+)/service-event/(?P<service_event>[a-zA-Z0-9-_/]+)$', msg.topic)
|
|
441
444
|
if match:
|
|
442
445
|
user_id: str = match.group('user_id')
|
|
443
446
|
vin: str = match.group('vin')
|
|
@@ -481,7 +484,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
481
484
|
# If charging state changed, fetch charging again
|
|
482
485
|
if old_charging_state != charging_state:
|
|
483
486
|
try:
|
|
484
|
-
self._skoda_connector.fetch_charging(vehicle)
|
|
487
|
+
self._skoda_connector.fetch_charging(vehicle, no_cache=True)
|
|
485
488
|
except CarConnectivityError as e:
|
|
486
489
|
LOG.error('Error while fetching charging: %s', e)
|
|
487
490
|
if 'timeToFinish' in data['data'] and data['data']['timeToFinish'] is not None \
|
|
@@ -507,12 +510,58 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
507
510
|
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
508
511
|
if isinstance(vehicle, SkodaVehicle):
|
|
509
512
|
try:
|
|
510
|
-
self._skoda_connector.fetch_air_conditioning(vehicle)
|
|
513
|
+
self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
|
|
511
514
|
except CarConnectivityError as e:
|
|
512
515
|
LOG.error('Error while fetching charging: %s', e)
|
|
513
516
|
LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
|
|
514
517
|
service_event, vin, user_id, msg.payload)
|
|
515
518
|
return
|
|
519
|
+
elif service_event == 'vehicle-status/access':
|
|
520
|
+
if 'name' in data and data['name'] == 'change-access':
|
|
521
|
+
if 'data' in data and data['data'] is not None:
|
|
522
|
+
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
523
|
+
if isinstance(vehicle, SkodaVehicle):
|
|
524
|
+
def delayed_access_function(vehicle: SkodaVehicle):
|
|
525
|
+
"""
|
|
526
|
+
Function to be executed after a delay of two seconds.
|
|
527
|
+
"""
|
|
528
|
+
vin = vehicle.id
|
|
529
|
+
self.delayed_access_function_timers.pop(vin)
|
|
530
|
+
if vehicle.capabilities is not None and vehicle.capabilities.enabled \
|
|
531
|
+
and vehicle.capabilities.has_capability('CHARGING') and isinstance(vehicle, SkodaElectricVehicle):
|
|
532
|
+
try:
|
|
533
|
+
self._skoda_connector.fetch_charging(vehicle, no_cache=True)
|
|
534
|
+
except CarConnectivityError as e:
|
|
535
|
+
LOG.error('Error while fetching charging: %s', e)
|
|
536
|
+
if vehicle.capabilities is not None and vehicle.capabilities.enabled \
|
|
537
|
+
and vehicle.capabilities.has_capability('PARKING_POSITION'):
|
|
538
|
+
try:
|
|
539
|
+
self._skoda_connector.fetch_position(vehicle, no_cache=True)
|
|
540
|
+
except CarConnectivityError as e:
|
|
541
|
+
LOG.error('Error while fetching position: %s', e)
|
|
542
|
+
if vehicle.capabilities is not None and vehicle.capabilities.enabled \
|
|
543
|
+
and vehicle.capabilities.has_capability('AIR_CONDITIONING'):
|
|
544
|
+
try:
|
|
545
|
+
self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
|
|
546
|
+
except CarConnectivityError as e:
|
|
547
|
+
LOG.error('Error while fetching air conditioning: %s', e)
|
|
548
|
+
try:
|
|
549
|
+
self._skoda_connector.fetch_vehicle_status_second_api(vehicle, no_cache=True)
|
|
550
|
+
except CarConnectivityError as e:
|
|
551
|
+
LOG.error('Error while fetching status second API: %s', e)
|
|
552
|
+
try:
|
|
553
|
+
self._skoda_connector.fetch_driving_range(vehicle, no_cache=True)
|
|
554
|
+
except CarConnectivityError as e:
|
|
555
|
+
LOG.error('Error while fetching driving range: %s', e)
|
|
556
|
+
|
|
557
|
+
if vin in self.delayed_access_function_timers:
|
|
558
|
+
self.delayed_access_function_timers[vin].cancel()
|
|
559
|
+
self.delayed_access_function_timers[vin] = threading.Timer(2.0, delayed_access_function, kwargs={'vehicle': vehicle})
|
|
560
|
+
self.delayed_access_function_timers[vin].start()
|
|
561
|
+
|
|
562
|
+
LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
|
|
563
|
+
service_event, vin, user_id, msg.payload)
|
|
564
|
+
return
|
|
516
565
|
LOG_API.info('Received unknown service event %s for vehicle %s from user %s: %s', service_event, vin, user_id, msg.payload)
|
|
517
566
|
return
|
|
518
567
|
# service_events
|
|
@@ -530,7 +579,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
530
579
|
if data['status'] == 'COMPLETED_SUCCESS':
|
|
531
580
|
LOG.debug('Received %s operation request for vehicle %s from user %s', operation_request, vin, user_id)
|
|
532
581
|
try:
|
|
533
|
-
self._skoda_connector.fetch_air_conditioning(vehicle)
|
|
582
|
+
self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
|
|
534
583
|
except CarConnectivityError as e:
|
|
535
584
|
LOG.error('Error while fetching air-conditioning: %s', e)
|
|
536
585
|
return
|
|
File without changes
|
|
File without changes
|
|
File without changes
|