carconnectivity-connector-skoda 0.1a14__py3-none-any.whl → 0.1a17__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.1a14.dist-info → carconnectivity_connector_skoda-0.1a17.dist-info}/METADATA +1 -1
- {carconnectivity_connector_skoda-0.1a14.dist-info → carconnectivity_connector_skoda-0.1a17.dist-info}/RECORD +11 -10
- carconnectivity_connectors/skoda/_version.py +1 -1
- carconnectivity_connectors/skoda/charging.py +72 -2
- carconnectivity_connectors/skoda/connector.py +116 -2
- carconnectivity_connectors/skoda/error.py +42 -0
- carconnectivity_connectors/skoda/mqtt_client.py +50 -19
- carconnectivity_connectors/skoda/vehicle.py +6 -0
- {carconnectivity_connector_skoda-0.1a14.dist-info → carconnectivity_connector_skoda-0.1a17.dist-info}/LICENSE +0 -0
- {carconnectivity_connector_skoda-0.1a14.dist-info → carconnectivity_connector_skoda-0.1a17.dist-info}/WHEEL +0 -0
- {carconnectivity_connector_skoda-0.1a14.dist-info → carconnectivity_connector_skoda-0.1a17.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
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=waXAIf0j4Aq__xvEJNJvHzQvbn3T7HTylT_B7dyZT10,409
|
|
3
3
|
carconnectivity_connectors/skoda/capability.py,sha256=JlNEaisVYF8qWv0wNDHTaas36uIpTIQ3NVR69wesiYQ,4513
|
|
4
|
-
carconnectivity_connectors/skoda/charging.py,sha256=
|
|
5
|
-
carconnectivity_connectors/skoda/connector.py,sha256=
|
|
6
|
-
carconnectivity_connectors/skoda/
|
|
7
|
-
carconnectivity_connectors/skoda/
|
|
4
|
+
carconnectivity_connectors/skoda/charging.py,sha256=OXy4Yr9bw5H_6BnGbvQTDyvxaIg8QN9YUog0dashdGE,6669
|
|
5
|
+
carconnectivity_connectors/skoda/connector.py,sha256=7307glMfF1EbhFzxrdomC_pvbHysyvq_cd4YoiHvG2M,79859
|
|
6
|
+
carconnectivity_connectors/skoda/error.py,sha256=xM8Ldgj-Biy793if3yTP5U7QIaBnOT7haEkxbXH4uYA,1962
|
|
7
|
+
carconnectivity_connectors/skoda/mqtt_client.py,sha256=AKRv2nmH3MfppFR3ub4Bg0oTZEhqxC-i9YVrmyHGq3U,34824
|
|
8
|
+
carconnectivity_connectors/skoda/vehicle.py,sha256=FbrhxZF-5TOUiPzUvryeFZrT-ie1XIyjRO4RbMymlJs,3115
|
|
8
9
|
carconnectivity_connectors/skoda/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
10
|
carconnectivity_connectors/skoda/auth/auth_util.py,sha256=dGLUbUre0HBsTg_Ii5vW34f8DLrCykYJYCyzEvUBBEE,4434
|
|
10
11
|
carconnectivity_connectors/skoda/auth/my_skoda_session.py,sha256=lSh23SFJs8opjmPwHTv-KNIKDep_WY4aItSP4Zq7bT8,10396
|
|
@@ -12,8 +13,8 @@ carconnectivity_connectors/skoda/auth/openid_session.py,sha256=LusWi2FZZIL3buodG
|
|
|
12
13
|
carconnectivity_connectors/skoda/auth/session_manager.py,sha256=Uf1vujuDBYUCAXhYToOsZkgbTtfmY3Qe0ICTfwomBpI,2899
|
|
13
14
|
carconnectivity_connectors/skoda/auth/skoda_web_session.py,sha256=cjzMkzx473Sh-4RgZAQULeRRcxB1MboddldCVM_y5LE,10640
|
|
14
15
|
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.
|
|
16
|
+
carconnectivity_connector_skoda-0.1a17.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
|
|
17
|
+
carconnectivity_connector_skoda-0.1a17.dist-info/METADATA,sha256=mlKJheSBMcIcszI4631ex5Eve1lzOt-a38eW1xRUBBs,5327
|
|
18
|
+
carconnectivity_connector_skoda-0.1a17.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
19
|
+
carconnectivity_connector_skoda-0.1a17.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
|
|
20
|
+
carconnectivity_connector_skoda-0.1a17.dist-info/RECORD,,
|
|
@@ -7,18 +7,47 @@ from typing import TYPE_CHECKING
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
|
|
9
9
|
from carconnectivity.charging import Charging
|
|
10
|
+
from carconnectivity.objects import GenericObject
|
|
11
|
+
from carconnectivity.vehicle import ElectricVehicle
|
|
12
|
+
from carconnectivity.attributes import BooleanAttribute, EnumAttribute, StringAttribute
|
|
13
|
+
|
|
14
|
+
from carconnectivity_connectors.skoda.error import Error
|
|
10
15
|
|
|
11
16
|
if TYPE_CHECKING:
|
|
12
|
-
from typing import Dict
|
|
17
|
+
from typing import Optional, Dict
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
class SkodaCharging(Charging): # pylint: disable=too-many-instance-attributes
|
|
16
21
|
"""
|
|
17
22
|
SkodaCharging class for handling Skoda vehicle charging information.
|
|
18
23
|
|
|
19
|
-
This class extends the Charging class and includes an enumeration of various
|
|
24
|
+
This class extends the Charging class and includes an enumeration of various
|
|
20
25
|
charging states specific to Skoda vehicles.
|
|
21
26
|
"""
|
|
27
|
+
def __init__(self, vehicle: ElectricVehicle | None = None, origin: Optional[Charging] = None) -> None:
|
|
28
|
+
if origin is not None:
|
|
29
|
+
super().__init__(origin=origin)
|
|
30
|
+
self.settings: Charging.Settings = SkodaCharging.Settings(origin=origin.settings)
|
|
31
|
+
else:
|
|
32
|
+
super().__init__(vehicle=vehicle)
|
|
33
|
+
self.settings: Charging.Settings = SkodaCharging.Settings(origin=self.settings)
|
|
34
|
+
self.errors: Dict[str, Error] = {}
|
|
35
|
+
self.is_in_saved_location: BooleanAttribute = BooleanAttribute("is_in_saved_location", parent=self)
|
|
36
|
+
|
|
37
|
+
class Settings(Charging.Settings):
|
|
38
|
+
"""
|
|
39
|
+
This class represents the settings for a skoda car charging.
|
|
40
|
+
"""
|
|
41
|
+
def __init__(self, parent: Optional[GenericObject] = None, origin: Optional[Charging.Settings] = None) -> None:
|
|
42
|
+
if origin is not None:
|
|
43
|
+
super().__init__(origin=origin)
|
|
44
|
+
else:
|
|
45
|
+
super().__init__(parent=parent)
|
|
46
|
+
self.preferred_charge_mode: EnumAttribute = EnumAttribute("preferred_charge_mode", parent=self)
|
|
47
|
+
self.available_charge_modes: StringAttribute = StringAttribute("available_charge_modes", parent=self)
|
|
48
|
+
self.charging_care_mode: EnumAttribute = EnumAttribute("charging_care_mode", parent=self)
|
|
49
|
+
self.battery_support: EnumAttribute = EnumAttribute("battery_support", parent=self)
|
|
50
|
+
|
|
22
51
|
class SkodaChargingState(Enum,):
|
|
23
52
|
"""
|
|
24
53
|
Enum representing the various charging states for a Skoda vehicle.
|
|
@@ -49,6 +78,47 @@ class SkodaCharging(Charging): # pylint: disable=too-many-instance-attributes
|
|
|
49
78
|
DISCHARGING = 'discharging'
|
|
50
79
|
UNKNOWN = 'unknown charging state'
|
|
51
80
|
|
|
81
|
+
class SkodaChargeMode(Enum,):
|
|
82
|
+
"""
|
|
83
|
+
Enum class representing different Skoda charge modes.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
HOME_STORAGE_CHARGING (str): Charge mode for home storage charging.
|
|
87
|
+
IMMEDIATE_DISCHARGING (str): Charge mode for immediate discharging.
|
|
88
|
+
ONLY_OWN_CURRENT (str): Charge mode for using only own current.
|
|
89
|
+
PREFERRED_CHARGING_TIMES (str): Charge mode for preferred charging times.
|
|
90
|
+
TIMER_CHARGING_WITH_CLIMATISATION (str): Charge mode for timer charging with climatisation.
|
|
91
|
+
TIMER (str): Charge mode for timer-based charging.
|
|
92
|
+
MANUAL (str): Charge mode for manual charging.
|
|
93
|
+
OFF (str): Charge mode for turning off charging.
|
|
94
|
+
"""
|
|
95
|
+
HOME_STORAGE_CHARGING = 'HOME_STORAGE_CHARGING'
|
|
96
|
+
IMMEDIATE_DISCHARGING = 'IMMEDIATE_DISCHARGING'
|
|
97
|
+
ONLY_OWN_CURRENT = 'ONLY_OWN_CURRENT'
|
|
98
|
+
PREFERRED_CHARGING_TIMES = 'PREFERRED_CHARGING_TIMES'
|
|
99
|
+
TIMER_CHARGING_WITH_CLIMATISATION = 'TIMER_CHARGING_WITH_CLIMATISATION'
|
|
100
|
+
TIMER = 'TIMER'
|
|
101
|
+
MANUAL = 'MANUAL'
|
|
102
|
+
OFF = 'OFF'
|
|
103
|
+
UNKNOWN = 'unknown charge mode'
|
|
104
|
+
|
|
105
|
+
class SkodaChargingCareMode(Enum,):
|
|
106
|
+
"""
|
|
107
|
+
Enum representing the charging care mode for Skoda vehicles.
|
|
108
|
+
"""
|
|
109
|
+
ACTIVATED = 'ACTIVATED'
|
|
110
|
+
DEACTIVATED = 'DEACTIVATED'
|
|
111
|
+
UNKNOWN = 'UNKNOWN'
|
|
112
|
+
|
|
113
|
+
class SkodaBatterySupport(Enum,):
|
|
114
|
+
"""
|
|
115
|
+
SkodaBatterySupport is an enumeration that represents the different states of battery support for Skoda vehicles.
|
|
116
|
+
"""
|
|
117
|
+
ENABLED = 'ENABLED'
|
|
118
|
+
DISABLED = 'DISABLED'
|
|
119
|
+
NOT_ALLOWED = 'NOT_ALLOWED'
|
|
120
|
+
UNKNOWN = 'UNKNOWN'
|
|
121
|
+
|
|
52
122
|
|
|
53
123
|
# Mapping of Skoda charging states to generic charging states
|
|
54
124
|
mapping_skoda_charging_state: Dict[SkodaCharging.SkodaChargingState, Charging.ChargingState] = {
|
|
@@ -31,11 +31,12 @@ from carconnectivity_connectors.skoda.auth.my_skoda_session import MySkodaSessio
|
|
|
31
31
|
from carconnectivity_connectors.skoda.vehicle import SkodaVehicle, SkodaElectricVehicle, SkodaCombustionVehicle, SkodaHybridVehicle
|
|
32
32
|
from carconnectivity_connectors.skoda.capability import Capability
|
|
33
33
|
from carconnectivity_connectors.skoda.charging import SkodaCharging, mapping_skoda_charging_state
|
|
34
|
+
from carconnectivity_connectors.skoda.error import Error
|
|
34
35
|
from carconnectivity_connectors.skoda._version import __version__
|
|
35
36
|
from carconnectivity_connectors.skoda.mqtt_client import SkodaMQTTClient
|
|
36
37
|
|
|
37
38
|
if TYPE_CHECKING:
|
|
38
|
-
from typing import Dict, List, Optional, Any
|
|
39
|
+
from typing import Dict, List, Optional, Any, Set
|
|
39
40
|
|
|
40
41
|
from carconnectivity.carconnectivity import CarConnectivity
|
|
41
42
|
|
|
@@ -340,6 +341,12 @@ class Connector(BaseConnector):
|
|
|
340
341
|
captured_at: datetime = robust_time_parse(data['carCapturedTimestamp'])
|
|
341
342
|
else:
|
|
342
343
|
raise APIError('Could not fetch charging, carCapturedTimestamp missing')
|
|
344
|
+
if 'isVehicleInSavedLocation' in data and data['isVehicleInSavedLocation'] is not None:
|
|
345
|
+
if vehicle.charging is not None:
|
|
346
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
347
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
348
|
+
# pylint: disable-next=protected-access
|
|
349
|
+
vehicle.charging.is_in_saved_location._set_value(data['isVehicleInSavedLocation'], measured=captured_at)
|
|
343
350
|
if 'status' in data and data['status'] is not None:
|
|
344
351
|
if 'state' in data['status'] and data['status']['state'] is not None:
|
|
345
352
|
if data['status']['state'] in [item.name for item in SkodaCharging.SkodaChargingState]:
|
|
@@ -404,7 +411,114 @@ class Connector(BaseConnector):
|
|
|
404
411
|
'state',
|
|
405
412
|
'chargeType',
|
|
406
413
|
'battery'})
|
|
407
|
-
|
|
414
|
+
if 'settings' in data and data['settings'] is not None:
|
|
415
|
+
if 'targetStateOfChargeInPercent' in data['settings'] and data['settings']['targetStateOfChargeInPercent'] is not None \
|
|
416
|
+
and vehicle.charging is not None and vehicle.charging.settings is not None:
|
|
417
|
+
# pylint: disable-next=protected-access
|
|
418
|
+
vehicle.charging.settings.target_level._set_value(value=data['settings']['targetStateOfChargeInPercent'], measured=captured_at)
|
|
419
|
+
else:
|
|
420
|
+
vehicle.charging.settings.target_level._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
421
|
+
if 'maxChargeCurrentAc' in data['settings'] and data['settings']['maxChargeCurrentAc'] is not None \
|
|
422
|
+
and vehicle.charging is not None and vehicle.charging.settings is not None:
|
|
423
|
+
if data['settings']['maxChargeCurrentAc'] == 'MAXIMUM':
|
|
424
|
+
vehicle.charging.settings.maximum_current._set_value(value=11, measured=captured_at) # pylint: disable=protected-access
|
|
425
|
+
elif data['settings']['maxChargeCurrentAc'] == 'REDUCED':
|
|
426
|
+
vehicle.charging.settings.maximum_current._set_value(value=6, measured=captured_at) # pylint: disable=protected-access
|
|
427
|
+
else:
|
|
428
|
+
LOG_API.info('Unknown maxChargeCurrentAc %s not in %s', data['settings']['maxChargeCurrentAc'], ['MAXIMUM', 'REDUCED'])
|
|
429
|
+
vehicle.charging.settings.maximum_current._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
430
|
+
else:
|
|
431
|
+
vehicle.charging.settings.maximum_current._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
432
|
+
if 'autoUnlockPlugWhenCharged' in data['settings'] and data['settings']['autoUnlockPlugWhenCharged'] is not None:
|
|
433
|
+
if data['settings']['autoUnlockPlugWhenCharged'] in ['ON', 'PERMANENT']:
|
|
434
|
+
vehicle.charging.settings.auto_unlock._set_value(True, measured=captured_at) # pylint: disable=protected-access
|
|
435
|
+
elif data['settings']['autoUnlockPlugWhenCharged'] == 'OFF':
|
|
436
|
+
vehicle.charging.settings.auto_unlock._set_value(False, measured=captured_at) # pylint: disable=protected-access
|
|
437
|
+
else:
|
|
438
|
+
LOG_API.info('Unknown autoUnlockPlugWhenCharged %s not in %s', data['settings']['autoUnlockPlugWhenCharged'],
|
|
439
|
+
['ON', 'PERMANENT', 'OFF'])
|
|
440
|
+
vehicle.charging.settings.auto_unlock._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
441
|
+
if 'preferredChargeMode' in data['settings'] and data['settings']['preferredChargeMode'] is not None:
|
|
442
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
443
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
444
|
+
if data['settings']['preferredChargeMode'] in [item.name for item in SkodaCharging.SkodaChargeMode]:
|
|
445
|
+
preferred_charge_mode: SkodaCharging.SkodaChargeMode = SkodaCharging.SkodaChargeMode[data['settings']['preferredChargeMode']]
|
|
446
|
+
else:
|
|
447
|
+
LOG_API.info('Unkown charge mode %s not in %s', data['settings']['preferredChargeMode'], str(SkodaCharging.SkodaChargeMode))
|
|
448
|
+
preferred_charge_mode = SkodaCharging.SkodaChargeMode.UNKNOWN
|
|
449
|
+
|
|
450
|
+
if isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
451
|
+
# pylint: disable-next=protected-access
|
|
452
|
+
vehicle.charging.settings.preferred_charge_mode._set_value(value=preferred_charge_mode, measured=captured_at)
|
|
453
|
+
else:
|
|
454
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
455
|
+
vehicle.charging.settings.preferred_charge_mode._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
456
|
+
if 'availableChargeModes' in data['settings'] and data['settings']['availableChargeModes'] is not None:
|
|
457
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
458
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
459
|
+
available_charge_modes: list[str] = data['settings']['availableChargeModes']
|
|
460
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
461
|
+
# pylint: disable-next=protected-access
|
|
462
|
+
vehicle.charging.settings.available_charge_modes._set_value('.'.join(available_charge_modes), measured=captured_at)
|
|
463
|
+
else:
|
|
464
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
465
|
+
vehicle.charging.settings.available_charge_modes._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
466
|
+
if 'chargingCareMode' in data['settings'] and data['settings']['chargingCareMode'] is not None:
|
|
467
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
468
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
469
|
+
if data['settings']['chargingCareMode'] in [item.name for item in SkodaCharging.SkodaChargingCareMode]:
|
|
470
|
+
charge_mode: SkodaCharging.SkodaChargingCareMode = SkodaCharging.SkodaChargingCareMode[data['settings']['chargingCareMode']]
|
|
471
|
+
else:
|
|
472
|
+
LOG_API.info('Unknown charging care mode %s not in %s', data['settings']['chargingCareMode'], str(SkodaCharging.SkodaChargingCareMode))
|
|
473
|
+
charge_mode = SkodaCharging.SkodaChargingCareMode.UNKNOWN
|
|
474
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
475
|
+
# pylint: disable-next=protected-access
|
|
476
|
+
vehicle.charging.settings.charging_care_mode._set_value(value=charge_mode, measured=captured_at)
|
|
477
|
+
else:
|
|
478
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
479
|
+
vehicle.charging.settings.charging_care_mode._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
480
|
+
if 'batterySupport' in data['settings'] and data['settings']['batterySupport'] is not None:
|
|
481
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
482
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
483
|
+
if data['settings']['batterySupport'] in [item.name for item in SkodaCharging.SkodaBatterySupport]:
|
|
484
|
+
battery_support: SkodaCharging.SkodaBatterySupport = SkodaCharging.SkodaBatterySupport[data['settings']['batterySupport']]
|
|
485
|
+
else:
|
|
486
|
+
LOG_API.info('Unknown battery support %s not in %s', data['settings']['batterySupport'], str(SkodaCharging.SkodaBatterySupport))
|
|
487
|
+
battery_support = SkodaCharging.SkodaBatterySupport.UNKNOWN
|
|
488
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
489
|
+
# pylint: disable-next=protected-access
|
|
490
|
+
vehicle.charging.settings.battery_support._set_value(value=battery_support, measured=captured_at)
|
|
491
|
+
else:
|
|
492
|
+
if vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
|
|
493
|
+
vehicle.charging.settings.battery_support._set_value(None, measured=captured_at) # pylint: disable=protected-access
|
|
494
|
+
log_extra_keys(LOG_API, 'settings', data['settings'], {'targetStateOfChargeInPercent', 'maxChargeCurrentAc', 'autoUnlockPlugWhenCharged',
|
|
495
|
+
'preferredChargeMode', 'availableChargeModes', 'chargingCareMode', 'batterySupport'})
|
|
496
|
+
if 'errors' in data and data['errors'] is not None:
|
|
497
|
+
found_errors: Set[str] = set()
|
|
498
|
+
if not isinstance(vehicle.charging, SkodaCharging):
|
|
499
|
+
vehicle.charging = SkodaCharging(origin=vehicle.charging)
|
|
500
|
+
for error_dict in data['errors']:
|
|
501
|
+
if 'type' in error_dict and error_dict['type'] is not None:
|
|
502
|
+
if error_dict['type'] not in vehicle.charging.errors:
|
|
503
|
+
error: Error = Error(object_id=error_dict['type'])
|
|
504
|
+
else:
|
|
505
|
+
error = vehicle.charging.errors[error_dict['type']]
|
|
506
|
+
if error_dict['type'] in [item.name for item in Error.ChargingError]:
|
|
507
|
+
error_type: Error.ChargingError = Error.ChargingError[error_dict['type']]
|
|
508
|
+
else:
|
|
509
|
+
LOG_API.info('Unknown charging error type %s not in %s', error_dict['type'], str(Error.ChargingError))
|
|
510
|
+
error_type = Error.ChargingError.UNKNOWN
|
|
511
|
+
error.type._set_value(error_type, measured=captured_at) # pylint: disable=protected-access
|
|
512
|
+
if 'description' in error_dict and error_dict['description'] is not None:
|
|
513
|
+
error.description._set_value(error_dict['description'], measured=captured_at) # pylint: disable=protected-access
|
|
514
|
+
log_extra_keys(LOG_API, 'errors', error_dict, {'type', 'description'})
|
|
515
|
+
if vehicle.charging is not None and vehicle.charging.errors is not None and len(vehicle.charging.errors) > 0:
|
|
516
|
+
for error_id in vehicle.charging.errors.keys()-found_errors:
|
|
517
|
+
vehicle.charging.errors.pop(error_id)
|
|
518
|
+
else:
|
|
519
|
+
if isinstance(vehicle.charging, SkodaCharging):
|
|
520
|
+
vehicle.charging.errors.clear()
|
|
521
|
+
log_extra_keys(LOG_API, 'charging data', data, {'carCapturedTimestamp', 'status', 'isVehicleInSavedLocation', 'errors', 'settings'})
|
|
408
522
|
return vehicle
|
|
409
523
|
|
|
410
524
|
def fetch_position(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Module for Skoda vehicle capability class."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
from carconnectivity.objects import GenericObject
|
|
8
|
+
from carconnectivity.attributes import EnumAttribute, StringAttribute
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Error(GenericObject):
|
|
15
|
+
"""
|
|
16
|
+
Represents an error object in the car connectivity context.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, object_id, parent: Optional[GenericObject] = None) -> None:
|
|
20
|
+
super().__init__(object_id, parent=parent)
|
|
21
|
+
self.type: EnumAttribute = EnumAttribute("type", parent=self)
|
|
22
|
+
self.description: StringAttribute = StringAttribute("description", parent=self)
|
|
23
|
+
|
|
24
|
+
class ChargingError(Enum):
|
|
25
|
+
"""
|
|
26
|
+
Enum representing various charging errors for Skoda car connectivity.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
STATUS_OF_CHARGING_NOT_AVAILABLE: Indicates that the status of charging is not available.
|
|
30
|
+
STATUS_OF_CONNECTION_NOT_AVAILABLE: Indicates that the status of connection is not available.
|
|
31
|
+
CARE_MODE_IS_NOT_AVAILABLE: Indicates that the care mode is not available.
|
|
32
|
+
AUTO_UNLOCK_IS_NOT_AVAILABLE: Indicates that the auto unlock feature is not available.
|
|
33
|
+
MAX_CHARGE_CURRENT_IS_NOT_AVAILABLE: Indicates that the maximum charge current setting is not available.
|
|
34
|
+
CHARGE_LIMIT_IS_NOT_AVAILABLE: Indicates that the charge limit setting is not available.
|
|
35
|
+
"""
|
|
36
|
+
STATUS_OF_CHARGING_NOT_AVAILABLE = 'STATUS_OF_CHARGING_NOT_AVAILABLE'
|
|
37
|
+
STATUS_OF_CONNECTION_NOT_AVAILABLE = 'STATUS_OF_CONNECTION_NOT_AVAILABLE'
|
|
38
|
+
CARE_MODE_IS_NOT_AVAILABLE = 'CARE_MODE_IS_NOT_AVAILABLE'
|
|
39
|
+
AUTO_UNLOCK_IS_NOT_AVAILABLE = 'AUTO_UNLOCK_IS_NOT_AVAILABLE'
|
|
40
|
+
MAX_CHARGE_CURRENT_IS_NOT_AVAILABLE = 'MAX_CHARGE_CURRENT_IS_NOT_AVAILABLE'
|
|
41
|
+
CHARGE_LIMIT_IS_NOT_AVAILABLE = 'CHARGE_LIMIT_IS_NOT_AVAILABLE'
|
|
42
|
+
UNKNOWN = 'UNKNOWN'
|
|
@@ -21,15 +21,22 @@ from carconnectivity.drive import ElectricDrive
|
|
|
21
21
|
from carconnectivity.util import robust_time_parse, log_extra_keys
|
|
22
22
|
from carconnectivity.charging import Charging
|
|
23
23
|
from carconnectivity.climatization import Climatization
|
|
24
|
+
from carconnectivity.units import Speed, Power
|
|
24
25
|
|
|
25
26
|
from carconnectivity_connectors.skoda.vehicle import SkodaVehicle, SkodaElectricVehicle
|
|
26
27
|
from carconnectivity_connectors.skoda.charging import SkodaCharging, mapping_skoda_charging_state
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
if TYPE_CHECKING:
|
|
30
|
-
from typing import Set, Dict, Any, Optional
|
|
31
|
+
from typing import Set, Dict, Any, Optional, List
|
|
31
32
|
from datetime import datetime
|
|
32
33
|
|
|
34
|
+
from paho.mqtt.client import MQTTMessage, DisconnectFlags, ConnectFlags
|
|
35
|
+
from paho.mqtt.reasoncodes import ReasonCode
|
|
36
|
+
from paho.mqtt.properties import Properties
|
|
37
|
+
|
|
38
|
+
from carconnectivity.attributes import GenericAttribute
|
|
39
|
+
|
|
33
40
|
from carconnectivity_connectors.skoda.connector import Connector
|
|
34
41
|
|
|
35
42
|
|
|
@@ -72,7 +79,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
72
79
|
"""
|
|
73
80
|
return super().connect(*args, host='mqtt.messagehub.de', port=8883, keepalive=60, **kwargs)
|
|
74
81
|
|
|
75
|
-
def _on_pre_connect_callback(self, client, userdata) -> None:
|
|
82
|
+
def _on_pre_connect_callback(self, client: Client, userdata: Any) -> None:
|
|
76
83
|
"""
|
|
77
84
|
Callback function that is called before the MQTT client connects to the broker.
|
|
78
85
|
|
|
@@ -94,7 +101,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
94
101
|
# pylint: disable-next=attribute-defined-outside-init # this is a false positive, password has a setter in super class
|
|
95
102
|
self._password = self._skoda_connector.session.access_token # This is a bit hacky but if password attribute is used here there is an Exception
|
|
96
103
|
|
|
97
|
-
def _on_carconnectivity_vehicle_enabled(self, element, flags):
|
|
104
|
+
def _on_carconnectivity_vehicle_enabled(self, element: GenericAttribute, flags: Observable.ObserverEvent) -> None:
|
|
98
105
|
"""
|
|
99
106
|
Handles the event when a vehicle is enabled or disabled in the car connectivity system.
|
|
100
107
|
|
|
@@ -252,7 +259,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
252
259
|
self.subscribed_topics.remove(topic)
|
|
253
260
|
LOG.debug('Unsubscribed from topic %s', topic)
|
|
254
261
|
|
|
255
|
-
def _on_connect_callback(self,
|
|
262
|
+
def _on_connect_callback(self, client: Client, obj: Any, flags: ConnectFlags, reason_code: ReasonCode, properties: Optional[Properties]) -> None:
|
|
256
263
|
"""
|
|
257
264
|
Callback function that is called when the MQTT client connects to the broker.
|
|
258
265
|
|
|
@@ -293,7 +300,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
293
300
|
- 159: Connection rate exceeded.
|
|
294
301
|
- Other: Generic connection error.
|
|
295
302
|
"""
|
|
296
|
-
del
|
|
303
|
+
del client # unused
|
|
297
304
|
del obj # unused
|
|
298
305
|
del flags # unused
|
|
299
306
|
del properties
|
|
@@ -351,8 +358,8 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
351
358
|
else:
|
|
352
359
|
LOG.error('Could not connect (%s)', reason_code)
|
|
353
360
|
|
|
354
|
-
def _on_disconnect_callback(self, client, userdata, flags, reason_code, properties) -> None:
|
|
355
|
-
"""
|
|
361
|
+
def _on_disconnect_callback(self, client: Client, userdata, flags: DisconnectFlags, reason_code: ReasonCode, properties: Optional[Properties]) -> None:
|
|
362
|
+
"""["Client", Any, DisconnectFlags, ReasonCode, Union[Properties, None]
|
|
356
363
|
Callback function that is called when the MQTT client disconnects.
|
|
357
364
|
|
|
358
365
|
This function handles the disconnection of the MQTT client and logs the appropriate
|
|
@@ -391,9 +398,9 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
391
398
|
elif reason_code == 160:
|
|
392
399
|
LOG.error('Client disconnected: Maximum connect time')
|
|
393
400
|
else:
|
|
394
|
-
LOG.error('Client unexpectedly disconnected (%d: %s), trying to reconnect', reason_code, reason_code)
|
|
401
|
+
LOG.error('Client unexpectedly disconnected (%d: %s), trying to reconnect', reason_code.value, reason_code.getName())
|
|
395
402
|
|
|
396
|
-
def _on_subscribe_callback(self,
|
|
403
|
+
def _on_subscribe_callback(self, client: Client, obj: Any, mid: int, reason_codes: List[ReasonCode], properties: Optional[Properties]) -> None:
|
|
397
404
|
"""
|
|
398
405
|
Callback function for MQTT subscription.
|
|
399
406
|
|
|
@@ -410,15 +417,15 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
410
417
|
Returns:
|
|
411
418
|
None
|
|
412
419
|
"""
|
|
413
|
-
del
|
|
420
|
+
del client # unused
|
|
414
421
|
del obj # unused
|
|
415
422
|
del properties # unused
|
|
416
423
|
if any(x in [0, 1, 2] for x in reason_codes):
|
|
417
424
|
LOG.debug('sucessfully subscribed to topic of mid %d', mid)
|
|
418
425
|
else:
|
|
419
|
-
LOG.error('Subscribe was not successfull (%s)', ', '.join(reason_codes))
|
|
426
|
+
LOG.error('Subscribe was not successfull (%s)', ', '.join([reason_code.getName() for reason_code in reason_codes]))
|
|
420
427
|
|
|
421
|
-
def _on_message_callback(self,
|
|
428
|
+
def _on_message_callback(self, client: Client, obj: Any, msg: MQTTMessage) -> None: # noqa: C901
|
|
422
429
|
"""
|
|
423
430
|
Callback function for handling incoming MQTT messages.
|
|
424
431
|
|
|
@@ -434,7 +441,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
434
441
|
Returns:
|
|
435
442
|
None
|
|
436
443
|
"""
|
|
437
|
-
del
|
|
444
|
+
del client # unused
|
|
438
445
|
del obj # unused
|
|
439
446
|
if len(msg.payload) == 0:
|
|
440
447
|
LOG_API.debug('MQTT topic %s: ignoring empty message', msg.topic)
|
|
@@ -474,9 +481,9 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
474
481
|
# pylint: disable-next=protected-access
|
|
475
482
|
vehicle.charging.type._set_value(value=Charging.ChargingType.OFF, measured=measured_at)
|
|
476
483
|
# pylint: disable-next=protected-access
|
|
477
|
-
vehicle.charging.rate._set_value(value=0, measured=measured_at)
|
|
484
|
+
vehicle.charging.rate._set_value(value=0, measured=measured_at, unit=Speed.KMH)
|
|
478
485
|
# pylint: disable-next=protected-access
|
|
479
|
-
vehicle.charging.power._set_value(value=0, measured=measured_at)
|
|
486
|
+
vehicle.charging.power._set_value(value=0, measured=measured_at, unit=Power.KW)
|
|
480
487
|
if 'soc' in data['data'] and data['data']['soc'] is not None:
|
|
481
488
|
electric_drive.level._set_value(measured=measured_at, value=data['data']['soc']) # pylint: disable=protected-access
|
|
482
489
|
if 'chargedRange' in data['data'] and data['data']['chargedRange'] is not None:
|
|
@@ -574,8 +581,15 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
574
581
|
operation_request: str = match.group('operation_request')
|
|
575
582
|
data: Dict[str, Any] = json.loads(msg.payload)
|
|
576
583
|
if data is not None:
|
|
577
|
-
|
|
578
|
-
|
|
584
|
+
vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
|
|
585
|
+
if operation_request == 'air-conditioning/set-air-conditioning-at-unlock' \
|
|
586
|
+
or operation_request == 'air-conditioning/set-air-conditioning-seats-heating' \
|
|
587
|
+
or operation_request == 'air-conditioning/set-air-conditioning-timers' \
|
|
588
|
+
or operation_request == 'air-conditioning/set-air-conditioning-without-external-power' \
|
|
589
|
+
or operation_request == 'air-conditioning/set-target-temperature' \
|
|
590
|
+
or operation_request == 'air-conditioning/start-stop-air-conditioning' \
|
|
591
|
+
or operation_request == 'air-conditioning/start-stop-window-heating' \
|
|
592
|
+
or operation_request == 'air-conditioning/windows-heating':
|
|
579
593
|
if isinstance(vehicle, SkodaVehicle):
|
|
580
594
|
if 'status' in data and data['status'] is not None:
|
|
581
595
|
if data['status'] == 'COMPLETED_SUCCESS':
|
|
@@ -585,6 +599,23 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
|
|
|
585
599
|
except CarConnectivityError as e:
|
|
586
600
|
LOG.error('Error while fetching air-conditioning: %s', e)
|
|
587
601
|
return
|
|
588
|
-
|
|
589
|
-
|
|
602
|
+
if operation_request == 'charging/start-stop-charging' \
|
|
603
|
+
or operation_request == 'charging/update-battery-support' \
|
|
604
|
+
or operation_request == 'charging/update-auto-unlock-plug' \
|
|
605
|
+
or operation_request == 'charging/update-care-mode' \
|
|
606
|
+
or operation_request == 'charging/update-charge-limit' \
|
|
607
|
+
or operation_request == 'charging/update-charge-mode' \
|
|
608
|
+
or operation_request == 'charging/update-charging-profiles' \
|
|
609
|
+
or operation_request == 'charging/update-charging-current':
|
|
610
|
+
if isinstance(vehicle, SkodaElectricVehicle):
|
|
611
|
+
if 'status' in data and data['status'] is not None:
|
|
612
|
+
if data['status'] == 'COMPLETED_SUCCESS':
|
|
613
|
+
LOG.debug('Received %s operation request for vehicle %s from user %s', operation_request, vin, user_id)
|
|
614
|
+
try:
|
|
615
|
+
self._skoda_connector.fetch_charging(vehicle, no_cache=True)
|
|
616
|
+
except CarConnectivityError as e:
|
|
617
|
+
LOG.error('Error while fetching charging: %s', e)
|
|
618
|
+
return
|
|
619
|
+
LOG_API.info('Received unknown operation request %s for vehicle %s from user %s: %s', operation_request, vin, user_id, msg.payload)
|
|
620
|
+
return
|
|
590
621
|
LOG_API.info('I don\'t understand message %s: %s', msg.topic, msg.payload)
|
|
@@ -3,8 +3,10 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from carconnectivity.vehicle import GenericVehicle, ElectricVehicle, CombustionVehicle, HybridVehicle
|
|
6
|
+
from carconnectivity.charging import Charging
|
|
6
7
|
|
|
7
8
|
from carconnectivity_connectors.skoda.capability import Capabilities
|
|
9
|
+
from carconnectivity_connectors.skoda.charging import SkodaCharging
|
|
8
10
|
|
|
9
11
|
if TYPE_CHECKING:
|
|
10
12
|
from typing import Optional
|
|
@@ -39,8 +41,12 @@ class SkodaElectricVehicle(ElectricVehicle, SkodaVehicle):
|
|
|
39
41
|
origin: Optional[SkodaVehicle] = None) -> None:
|
|
40
42
|
if origin is not None:
|
|
41
43
|
super().__init__(origin=origin)
|
|
44
|
+
if isinstance(origin, ElectricVehicle):
|
|
45
|
+
self.charging: Charging = SkodaCharging(origin=origin.charging)
|
|
46
|
+
self.charging.parent = self
|
|
42
47
|
else:
|
|
43
48
|
super().__init__(vin=vin, garage=garage, managing_connector=managing_connector)
|
|
49
|
+
self.charging: Charging = SkodaCharging(vehicle=self)
|
|
44
50
|
|
|
45
51
|
|
|
46
52
|
class SkodaCombustionVehicle(CombustionVehicle, SkodaVehicle):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|