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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-skoda
3
- Version: 0.1a14
3
+ Version: 0.1a17
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -1,10 +1,11 @@
1
1
  carconnectivity_connectors/skoda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- carconnectivity_connectors/skoda/_version.py,sha256=ydJdzW-btPcfSrfx2Va0JEeRefzQRak0BrHC2KuWcaU,409
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=oDHxZxrfTMvtYCJxmGfKFeWVMH4ceQ5HTKRAspnsunU,3312
5
- carconnectivity_connectors/skoda/connector.py,sha256=Z7CZclSC8lg0Rc5Zf2Vp9ATgXxACq_aTpxJxfe2EEsw,69140
6
- carconnectivity_connectors/skoda/mqtt_client.py,sha256=oFyuMWchYSdu_St4VzcGsCUzsgUzYdA2_gmzbilgqL8,32105
7
- carconnectivity_connectors/skoda/vehicle.py,sha256=H3GRDNimMghFwFi--y9BsgoSK3pMibNf_l6SsDN6gvQ,2759
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.1a14.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
16
- carconnectivity_connector_skoda-0.1a14.dist-info/METADATA,sha256=65N4TiZujxrtbetLvzRlpY7Jntm3cQRqn4MNpjWkXyY,5327
17
- carconnectivity_connector_skoda-0.1a14.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
- carconnectivity_connector_skoda-0.1a14.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
19
- carconnectivity_connector_skoda-0.1a14.dist-info/RECORD,,
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,,
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1a14'
15
+ __version__ = version = '0.1a17'
16
16
  __version_tuple__ = version_tuple = (0, 1)
@@ -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
- log_extra_keys(LOG_API, 'charging data', data, {'carCapturedTimestamp', 'status'})
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, mqttc, obj, flags, reason_code, properties) -> None:
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 mqttc # unused
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, mqttc, obj, mid, reason_codes, properties) -> None:
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 mqttc # unused
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, mqttc, obj, msg) -> None: # noqa: C901
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 mqttc # unused
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
- if operation_request == 'air-conditioning/start-stop-air-conditioning':
578
- vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
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
- LOG_API.info('Received unknown operation request %s for vehicle %s from user %s: %s', operation_request, vin, user_id, msg.payload)
589
- return
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):