carconnectivity-connector-skoda 0.1a17__tar.gz → 0.1a18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (37) hide show
  1. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/PKG-INFO +1 -1
  2. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connector_skoda.egg-info/PKG-INFO +1 -1
  3. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connector_skoda.egg-info/SOURCES.txt +1 -0
  4. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/_version.py +1 -1
  5. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/charging.py +3 -3
  6. carconnectivity_connector_skoda-0.1a18/src/carconnectivity_connectors/skoda/climatization.py +41 -0
  7. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/connector.py +191 -11
  8. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/error.py +10 -0
  9. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/mqtt_client.py +26 -0
  10. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.flake8 +0 -0
  11. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  12. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  13. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/dependabot.yml +0 -0
  14. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/workflows/build.yml +0 -0
  15. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/workflows/build_and_publish.yml +0 -0
  16. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.github/workflows/codeql-analysis.yml +0 -0
  17. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/.gitignore +0 -0
  18. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/LICENSE +0 -0
  19. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/Makefile +0 -0
  20. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/README.md +0 -0
  21. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/doc/Config.md +0 -0
  22. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/pyproject.toml +0 -0
  23. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/setup.cfg +0 -0
  24. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/setup_requirements.txt +0 -0
  25. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connector_skoda.egg-info/dependency_links.txt +0 -0
  26. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connector_skoda.egg-info/requires.txt +0 -0
  27. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connector_skoda.egg-info/top_level.txt +0 -0
  28. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/__init__.py +0 -0
  29. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/__init__.py +0 -0
  30. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/auth_util.py +0 -0
  31. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py +0 -0
  32. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/my_skoda_session.py +0 -0
  33. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/openid_session.py +0 -0
  34. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/session_manager.py +0 -0
  35. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/auth/skoda_web_session.py +0 -0
  36. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/capability.py +0 -0
  37. {carconnectivity_connector_skoda-0.1a17 → carconnectivity_connector_skoda-0.1a18}/src/carconnectivity_connectors/skoda/vehicle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-skoda
3
- Version: 0.1a17
3
+ Version: 0.1a18
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: carconnectivity-connector-skoda
3
- Version: 0.1a17
3
+ Version: 0.1a18
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -21,6 +21,7 @@ src/carconnectivity_connectors/skoda/__init__.py
21
21
  src/carconnectivity_connectors/skoda/_version.py
22
22
  src/carconnectivity_connectors/skoda/capability.py
23
23
  src/carconnectivity_connectors/skoda/charging.py
24
+ src/carconnectivity_connectors/skoda/climatization.py
24
25
  src/carconnectivity_connectors/skoda/connector.py
25
26
  src/carconnectivity_connectors/skoda/error.py
26
27
  src/carconnectivity_connectors/skoda/mqtt_client.py
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1a17'
15
+ __version__ = version = '0.1a18'
16
16
  __version_tuple__ = version_tuple = (0, 1)
@@ -97,9 +97,9 @@ class SkodaCharging(Charging): # pylint: disable=too-many-instance-attributes
97
97
  ONLY_OWN_CURRENT = 'ONLY_OWN_CURRENT'
98
98
  PREFERRED_CHARGING_TIMES = 'PREFERRED_CHARGING_TIMES'
99
99
  TIMER_CHARGING_WITH_CLIMATISATION = 'TIMER_CHARGING_WITH_CLIMATISATION'
100
- TIMER = 'TIMER'
101
- MANUAL = 'MANUAL'
102
- OFF = 'OFF'
100
+ TIMER = 'timer'
101
+ MANUAL = 'manual'
102
+ OFF = 'off'
103
103
  UNKNOWN = 'unknown charge mode'
104
104
 
105
105
  class SkodaChargingCareMode(Enum,):
@@ -0,0 +1,41 @@
1
+ """
2
+ Module for charging for skoda vehicles.
3
+ """
4
+ from __future__ import annotations
5
+ from typing import TYPE_CHECKING
6
+
7
+ from carconnectivity.climatization import Climatization
8
+ from carconnectivity.objects import GenericObject
9
+ from carconnectivity.vehicle import ElectricVehicle
10
+
11
+ from carconnectivity_connectors.skoda.error import Error
12
+
13
+ if TYPE_CHECKING:
14
+ from typing import Optional, Dict
15
+
16
+
17
+ class SkodaClimatization(Climatization): # pylint: disable=too-many-instance-attributes
18
+ """
19
+ SkodaClimatization class for handling Skoda vehicle climatization information.
20
+
21
+ This class extends the Climatization class and includes an enumeration of various
22
+ charging states specific to Skoda vehicles.
23
+ """
24
+ def __init__(self, vehicle: ElectricVehicle | None = None, origin: Optional[Climatization] = None) -> None:
25
+ if origin is not None:
26
+ super().__init__(origin=origin)
27
+ self.settings: Climatization.Settings = SkodaClimatization.Settings(origin=origin.settings)
28
+ else:
29
+ super().__init__(vehicle=vehicle)
30
+ self.settings: Climatization.Settings = SkodaClimatization.Settings(origin=self.settings)
31
+ self.errors: Dict[str, Error] = {}
32
+
33
+ class Settings(Climatization.Settings):
34
+ """
35
+ This class represents the settings for a skoda car climatiation.
36
+ """
37
+ def __init__(self, parent: Optional[GenericObject] = None, origin: Optional[Climatization.Settings] = None) -> None:
38
+ if origin is not None:
39
+ super().__init__(origin=origin)
40
+ else:
41
+ super().__init__(parent=parent)
@@ -15,9 +15,9 @@ from carconnectivity.errors import AuthenticationError, TooManyRequestsError, Re
15
15
  TemporaryAuthenticationError, ConfigurationError
16
16
  from carconnectivity.util import robust_time_parse, log_extra_keys, config_remove_credentials
17
17
  from carconnectivity.units import Length, Speed, Power, Temperature
18
- # from carconnectivity.doors import Doors
19
- # from carconnectivity.windows import Windows
20
- # from carconnectivity.lights import Lights
18
+ from carconnectivity.doors import Doors
19
+ from carconnectivity.windows import Windows
20
+ from carconnectivity.lights import Lights
21
21
  from carconnectivity.drive import GenericDrive, ElectricDrive, CombustionDrive
22
22
  from carconnectivity.attributes import BooleanAttribute, DurationAttribute
23
23
  from carconnectivity.charging import Charging
@@ -31,6 +31,7 @@ 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.climatization import SkodaClimatization
34
35
  from carconnectivity_connectors.skoda.error import Error
35
36
  from carconnectivity_connectors.skoda._version import __version__
36
37
  from carconnectivity_connectors.skoda.mqtt_client import SkodaMQTTClient
@@ -309,6 +310,7 @@ class Connector(BaseConnector):
309
310
  for vin in set(garage.list_vehicle_vins()):
310
311
  vehicle_to_update: Optional[GenericVehicle] = garage.get_vehicle(vin)
311
312
  if vehicle_to_update is not None and isinstance(vehicle_to_update, SkodaVehicle) and vehicle_to_update.is_managed_by_connector(self):
313
+ vehicle_to_update = self.fetch_vehicle_status(vehicle_to_update)
312
314
  vehicle_to_update = self.fetch_driving_range(vehicle_to_update)
313
315
  if vehicle_to_update.capabilities is not None and vehicle_to_update.capabilities.enabled:
314
316
  if vehicle_to_update.capabilities.has_capability('PARKING_POSITION'):
@@ -636,15 +638,16 @@ class Connector(BaseConnector):
636
638
  LOG_API.info('Unknown temperature unit for targetTemperature in air-conditioning %s', data['targetTemperature']['unitInCar'])
637
639
  if 'temperatureValue' in data['targetTemperature'] and data['targetTemperature']['temperatureValue'] is not None:
638
640
  # pylint: disable-next=protected-access
639
- vehicle.climatization.target_temperature._set_value(value=data['targetTemperature']['temperatureValue'],
640
- measured=captured_at,
641
- unit=unit)
641
+ vehicle.climatization.settings.target_temperature._set_value(value=data['targetTemperature']['temperatureValue'],
642
+ measured=captured_at,
643
+ unit=unit)
642
644
  else:
643
- vehicle.climatization.target_temperature._set_value(value=None, measured=captured_at, unit=unit) # pylint: disable=protected-access
645
+ # pylint: disable-next=protected-access
646
+ vehicle.climatization.settings.target_temperature._set_value(value=None, measured=captured_at, unit=unit)
644
647
  log_extra_keys(LOG_API, 'targetTemperature', data['targetTemperature'], {'unitInCar', 'temperatureValue'})
645
648
  else:
646
649
  # pylint: disable-next=protected-access
647
- vehicle.climatization.target_temperature._set_value(value=None, measured=captured_at, unit=Temperature.UNKNOWN)
650
+ vehicle.climatization.settings.target_temperature._set_value(value=None, measured=captured_at, unit=Temperature.UNKNOWN)
648
651
  if 'outsideTemperature' in data and data['outsideTemperature'] is not None:
649
652
  if 'carCapturedTimestamp' in data['outsideTemperature'] and data['outsideTemperature']['carCapturedTimestamp'] is not None:
650
653
  outside_captured_at: datetime = robust_time_parse(data['outsideTemperature']['carCapturedTimestamp'])
@@ -659,7 +662,7 @@ class Connector(BaseConnector):
659
662
  elif data['outsideTemperature']['temperatureUnit'] == 'KELVIN':
660
663
  unit = Temperature.K
661
664
  else:
662
- LOG_API.info('Unknown temperature unit for outsideTemperature in air-conditioning %s', data['targetTemperature']['temperatureUnit'])
665
+ LOG_API.info('Unknown temperature unit for outsideTemperature in air-conditioning %s', data['outsideTemperature']['temperatureUnit'])
663
666
  if 'temperatureValue' in data['outsideTemperature'] and data['outsideTemperature']['temperatureValue'] is not None:
664
667
  # pylint: disable-next=protected-access
665
668
  vehicle.outside_temperature._set_value(value=data['outsideTemperature']['temperatureValue'],
@@ -674,6 +677,66 @@ class Connector(BaseConnector):
674
677
  log_extra_keys(LOG_API, 'targetTemperature', data['outsideTemperature'], {'carCapturedTimestamp', 'temperatureUnit', 'temperatureValue'})
675
678
  else:
676
679
  vehicle.outside_temperature._set_value(value=None, measured=None, unit=Temperature.UNKNOWN) # pylint: disable=protected-access
680
+ if 'airConditioningAtUnlock' in data and data['airConditioningAtUnlock'] is not None:
681
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
682
+ if data['airConditioningAtUnlock'] is True:
683
+ # pylint: disable-next=protected-access
684
+ vehicle.climatization.settings.climatization_at_unlock._set_value(True, measured=captured_at)
685
+ elif data['airConditioningAtUnlock'] is False:
686
+ # pylint: disable-next=protected-access
687
+ vehicle.climatization.settings.climatization_at_unlock._set_value(False, measured=captured_at)
688
+ else:
689
+ # pylint: disable-next=protected-access
690
+ vehicle.climatization.settings.climatization_at_unlock._set_value(None, measured=captured_at)
691
+ else:
692
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
693
+ # pylint: disable-next=protected-access
694
+ vehicle.climatization.settings.climatization_at_unlock._set_value(None, measured=captured_at)
695
+ if 'steeringWheelPosition' in data and data['steeringWheelPosition'] is not None:
696
+ if vehicle.specification is not None:
697
+ if data['steeringWheelPosition'] in [item.name for item in GenericVehicle.VehicleSpecification.SteeringPosition]:
698
+ steering_wheel_position: GenericVehicle.VehicleSpecification.SteeringPosition = \
699
+ GenericVehicle.VehicleSpecification.SteeringPosition[data['steeringWheelPosition']]
700
+ else:
701
+ LOG_API.info('Unknown steering wheel position %s not in %s', data['steeringWheelPosition'],
702
+ str(GenericVehicle.VehicleSpecification.SteeringPosition))
703
+ steering_wheel_position = GenericVehicle.VehicleSpecification.SteeringPosition.UNKNOWN
704
+ # pylint: disable-next=protected-access
705
+ vehicle.specification.steering_wheel_position._set_value(value=steering_wheel_position, measured=captured_at)
706
+ else:
707
+ if vehicle.specification is not None:
708
+ # pylint: disable-next=protected-access
709
+ vehicle.specification.steering_wheel_position._set_value(None, measured=captured_at)
710
+ if 'windowHeatingEnabled' in data and data['windowHeatingEnabled'] is not None:
711
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
712
+ if data['windowHeatingEnabled'] is True:
713
+ # pylint: disable-next=protected-access
714
+ vehicle.climatization.settings.window_heating._set_value(True, measured=captured_at)
715
+ elif data['windowHeatingEnabled'] is False:
716
+ # pylint: disable-next=protected-access
717
+ vehicle.climatization.settings.window_heating._set_value(False, measured=captured_at)
718
+ else:
719
+ # pylint: disable-next=protected-access
720
+ vehicle.climatization.settings.window_heating._set_value(None, measured=captured_at)
721
+ else:
722
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
723
+ # pylint: disable-next=protected-access
724
+ vehicle.climatization.settings.window_heating._set_value(None, measured=captured_at)
725
+ if 'seatHeatingActivated' in data and data['seatHeatingActivated'] is not None:
726
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
727
+ if data['seatHeatingActivated'] is True:
728
+ # pylint: disable-next=protected-access
729
+ vehicle.climatization.settings.seat_heating._set_value(True, measured=captured_at)
730
+ elif data['seatHeatingActivated'] is False:
731
+ # pylint: disable-next=protected-access
732
+ vehicle.climatization.settings.seat_heating._set_value(False, measured=captured_at)
733
+ else:
734
+ # pylint: disable-next=protected-access
735
+ vehicle.climatization.settings.seat_heating._set_value(None, measured=captured_at)
736
+ else:
737
+ if vehicle.climatization is not None and vehicle.climatization.settings is not None:
738
+ # pylint: disable-next=protected-access
739
+ vehicle.climatization.settings.seat_heating._set_value(None, measured=captured_at)
677
740
  if isinstance(vehicle, SkodaElectricVehicle):
678
741
  if 'chargerConnectionState' in data and data['chargerConnectionState'] is not None \
679
742
  and vehicle.charging is not None and vehicle.charging.connector is not None:
@@ -707,9 +770,35 @@ class Connector(BaseConnector):
707
770
  vehicle.charging.connector.lock_state._set_value(value=None, measured=captured_at)
708
771
  if 'windowHeatingState' in data and data['windowHeatingState'] is not None:
709
772
  pass
710
- log_extra_keys(LOG_API, 'air-condition', data, {'carCapturedTimestamp', 'state', 'estimatedDateTimeToReachTargetTemperature'
773
+ if 'errors' in data and data['errors'] is not None:
774
+ found_errors: Set[str] = set()
775
+ if not isinstance(vehicle.climatization, SkodaClimatization):
776
+ vehicle.climatization = SkodaClimatization(origin=vehicle.climatization)
777
+ for error_dict in data['errors']:
778
+ if 'type' in error_dict and error_dict['type'] is not None:
779
+ if error_dict['type'] not in vehicle.climatization.errors:
780
+ error: Error = Error(object_id=error_dict['type'])
781
+ else:
782
+ error = vehicle.climatization.errors[error_dict['type']]
783
+ if error_dict['type'] in [item.name for item in Error.ClimatizationError]:
784
+ error_type: Error.ClimatizationError = Error.ClimatizationError[error_dict['type']]
785
+ else:
786
+ LOG_API.info('Unknown climatization error type %s not in %s', error_dict['type'], str(Error.ClimatizationError))
787
+ error_type = Error.ClimatizationError.UNKNOWN
788
+ error.type._set_value(error_type, measured=captured_at) # pylint: disable=protected-access
789
+ if 'description' in error_dict and error_dict['description'] is not None:
790
+ error.description._set_value(error_dict['description'], measured=captured_at) # pylint: disable=protected-access
791
+ log_extra_keys(LOG_API, 'errors', error_dict, {'type', 'description'})
792
+ if vehicle.climatization is not None and vehicle.climatization.errors is not None and len(vehicle.climatization.errors) > 0:
793
+ for error_id in vehicle.climatization.errors.keys()-found_errors:
794
+ vehicle.climatization.errors.pop(error_id)
795
+ else:
796
+ if isinstance(vehicle.climatization, SkodaClimatization):
797
+ vehicle.climatization.errors.clear()
798
+ log_extra_keys(LOG_API, 'air-condition', data, {'carCapturedTimestamp', 'state', 'estimatedDateTimeToReachTargetTemperature',
711
799
  'targetTemperature', 'outsideTemperature', 'chargerConnectionState',
712
- 'chargerLockState'})
800
+ 'chargerLockState', 'airConditioningAtUnlock', 'steeringWheelPosition',
801
+ 'windowHeatingEnabled', 'seatHeatingActivated', 'errors'})
713
802
  return vehicle
714
803
 
715
804
  def fetch_vehicle_details(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
@@ -875,6 +964,97 @@ class Connector(BaseConnector):
875
964
  'secondaryEngineRange'})
876
965
  return vehicle
877
966
 
967
+ def fetch_vehicle_status(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
968
+ """
969
+ Fetches the status of a vehicle from other Skoda API.
970
+
971
+ Args:
972
+ vehicle (GenericVehicle): The vehicle object containing the VIN.
973
+
974
+ Returns:
975
+ None
976
+ """
977
+ vin = vehicle.vin.value
978
+ if vin is None:
979
+ raise APIError('VIN is missing')
980
+ url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
981
+ vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
982
+ if vehicle_status_data:
983
+ captured_at: datetime = robust_time_parse(vehicle_status_data['carCapturedTimestamp'])
984
+ if 'overall' in vehicle_status_data and vehicle_status_data['overall'] is not None:
985
+ if 'doorsLocked' in vehicle_status_data['overall'] and vehicle_status_data['overall']['doorsLocked'] is not None \
986
+ and vehicle.doors is not None:
987
+ if vehicle_status_data['overall']['doorsLocked'] == 'YES':
988
+ vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
989
+ vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
990
+ elif vehicle_status_data['overall']['doorsLocked'] == 'OPENED':
991
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
992
+ vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
993
+ elif vehicle_status_data['overall']['doorsLocked'] == 'UNLOCKED':
994
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
995
+ vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
996
+ elif vehicle_status_data['overall']['doorsLocked'] == 'TRUNK_OPENED':
997
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
998
+ vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
999
+ elif vehicle_status_data['overall']['doorsLocked'] == 'UNKNOWN':
1000
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1001
+ vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1002
+ else:
1003
+ LOG_API.info('Unknown doorsLocked state %s', vehicle_status_data['overall']['doorsLocked'])
1004
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1005
+ vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1006
+ if 'locked' in vehicle_status_data['overall'] and vehicle_status_data['overall']['locked'] is not None:
1007
+ if vehicle_status_data['overall']['locked'] == 'YES':
1008
+ vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
1009
+ elif vehicle_status_data['overall']['locked'] == 'NO':
1010
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
1011
+ elif vehicle_status_data['overall']['locked'] == 'UNKNOWN':
1012
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1013
+ else:
1014
+ LOG_API.info('Unknown locked state %s', vehicle_status_data['overall']['locked'])
1015
+ vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1016
+ if 'doors' in vehicle_status_data['overall'] and vehicle_status_data['overall']['doors'] is not None:
1017
+ if vehicle_status_data['overall']['doors'] == 'CLOSED':
1018
+ vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1019
+ elif vehicle_status_data['overall']['doors'] == 'OPEN':
1020
+ vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1021
+ elif vehicle_status_data['overall']['doors'] == 'UNSUPPORTED':
1022
+ vehicle.doors.open_state._set_value(Doors.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
1023
+ elif vehicle_status_data['overall']['doors'] == 'UNKNOWN':
1024
+ vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1025
+ else:
1026
+ LOG_API.info('Unknown doors state %s', vehicle_status_data['overall']['doors'])
1027
+ vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1028
+ if 'windows' in vehicle_status_data['overall'] and vehicle_status_data['overall']['windows'] is not None:
1029
+ if vehicle_status_data['overall']['windows'] == 'CLOSED':
1030
+ vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1031
+ elif vehicle_status_data['overall']['windows'] == 'OPEN':
1032
+ vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1033
+ elif vehicle_status_data['overall']['windows'] == 'UNKNOWN':
1034
+ vehicle.windows.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1035
+ elif vehicle_status_data['overall']['windows'] == 'UNSUPPORTED':
1036
+ vehicle.windows.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
1037
+ else:
1038
+ LOG_API.info('Unknown windows state %s', vehicle_status_data['overall']['windows'])
1039
+ vehicle.windows.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1040
+ if 'lights' in vehicle_status_data['overall'] and vehicle_status_data['overall']['lights'] is not None:
1041
+ if vehicle_status_data['overall']['lights'] == 'ON':
1042
+ vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
1043
+ elif vehicle_status_data['overall']['lights'] == 'OFF':
1044
+ vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
1045
+ elif vehicle_status_data['overall']['lights'] == 'UNKNOWN':
1046
+ vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1047
+ else:
1048
+ LOG_API.info('Unknown lights state %s', vehicle_status_data['overall']['lights'])
1049
+ vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1050
+ log_extra_keys(LOG_API, 'status overall', vehicle_status_data['overall'], {'doorsLocked',
1051
+ 'locked',
1052
+ 'doors',
1053
+ 'windows',
1054
+ 'lights'})
1055
+ log_extra_keys(LOG_API, f'/api/v2/vehicle-status/{vin}', vehicle_status_data, {'overall', 'carCapturedTimestamp'})
1056
+ return vehicle
1057
+
878
1058
  # def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
879
1059
  # """
880
1060
  # Fetches the status of a vehicle from other Skoda API.
@@ -40,3 +40,13 @@ class Error(GenericObject):
40
40
  MAX_CHARGE_CURRENT_IS_NOT_AVAILABLE = 'MAX_CHARGE_CURRENT_IS_NOT_AVAILABLE'
41
41
  CHARGE_LIMIT_IS_NOT_AVAILABLE = 'CHARGE_LIMIT_IS_NOT_AVAILABLE'
42
42
  UNKNOWN = 'UNKNOWN'
43
+
44
+ class ClimatizationError(Enum):
45
+ """
46
+ ClimatizationError is an enumeration for representing various errors
47
+ related to the climatization system in a Skoda car.
48
+
49
+ This enum can be extended to include specific error codes and messages
50
+ that correspond to different climatization issues.
51
+ """
52
+ UNKNOWN = 'UNKNOWN'
@@ -468,6 +468,15 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
468
468
  if electric_drive is not None:
469
469
  charging_state: Optional[Charging.ChargingState] = vehicle.charging.state.value
470
470
  old_charging_state: Optional[Charging.ChargingState] = charging_state
471
+ if 'mode' in data['data'] and data['data']['mode'] is not None \
472
+ and vehicle.charging is not None and isinstance(vehicle.charging.settings, SkodaCharging.Settings):
473
+ if data['data']['mode'] in SkodaCharging.SkodaChargeMode:
474
+ skoda_charging_mode = SkodaCharging.SkodaChargeMode(data['data']['mode'])
475
+ else:
476
+ LOG_API.info('Unkown charging mode %s not in %s', data['data']['mode'], str(SkodaCharging.SkodaChargeMode))
477
+ skoda_charging_mode = Charging.ChargingState.UNKNOWN
478
+ # pylint: disable-next=protected-access
479
+ vehicle.charging.settings.preferred_charge_mode._set_value(value=skoda_charging_mode, measured=measured_at)
471
480
  if 'state' in data['data'] and data['data']['state'] is not None:
472
481
  if data['data']['state'] in [item.value for item in SkodaCharging.SkodaChargingState]:
473
482
  skoda_charging_state = SkodaCharging.SkodaChargingState(data['data']['state'])
@@ -544,6 +553,10 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
544
553
  """
545
554
  vin = vehicle.id
546
555
  self.delayed_access_function_timers.pop(vin)
556
+ try:
557
+ self._skoda_connector.fetch_vehicle_status(vehicle, no_cache=True)
558
+ except CarConnectivityError as e:
559
+ LOG.error('Error while fetching vehicle status: %s', e)
547
560
  if vehicle.capabilities is not None and vehicle.capabilities.enabled \
548
561
  and vehicle.capabilities.has_capability('CHARGING') and isinstance(vehicle, SkodaElectricVehicle):
549
562
  try:
@@ -568,6 +581,19 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
568
581
  self.delayed_access_function_timers[vin] = threading.Timer(2.0, delayed_access_function, kwargs={'vehicle': vehicle})
569
582
  self.delayed_access_function_timers[vin].start()
570
583
 
584
+ LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
585
+ service_event, vin, user_id, msg.payload)
586
+ return
587
+ elif service_event == 'vehicle-status/lights':
588
+ if 'name' in data and data['name'] == 'change-lights':
589
+ if 'data' in data and data['data'] is not None:
590
+ vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
591
+ if isinstance(vehicle, SkodaVehicle):
592
+ try:
593
+ self._skoda_connector.fetch_vehicle_status(vehicle, no_cache=True)
594
+ except CarConnectivityError as e:
595
+ LOG.error('Error while fetching vehicle status: %s', e)
596
+
571
597
  LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
572
598
  service_event, vin, user_id, msg.payload)
573
599
  return