carconnectivity-connector-skoda 0.1a11__py3-none-any.whl → 0.1a13__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.1a11
3
+ Version: 0.1a13
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -1,9 +1,9 @@
1
1
  carconnectivity_connectors/skoda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- carconnectivity_connectors/skoda/_version.py,sha256=lXj09wNlQE2ygonVVc_Fk2FN_1_4nx6sHnElAwbvzHM,409
2
+ carconnectivity_connectors/skoda/_version.py,sha256=87o_kQQRIfRYZbD8Vrp3tNP9bKGf1QZJgBdyeWeQUXI,409
3
3
  carconnectivity_connectors/skoda/capability.py,sha256=JlNEaisVYF8qWv0wNDHTaas36uIpTIQ3NVR69wesiYQ,4513
4
4
  carconnectivity_connectors/skoda/charging.py,sha256=oDHxZxrfTMvtYCJxmGfKFeWVMH4ceQ5HTKRAspnsunU,3312
5
- carconnectivity_connectors/skoda/connector.py,sha256=xiPPT6XTVWsLvu0iqZvSPpgtHm3DrR1TKUL4d4NRz2Y,62158
6
- carconnectivity_connectors/skoda/mqtt_client.py,sha256=ZB56Za1k5vbxQPl5qCvukE46Tq1O0-Cn19kBz_bDJZM,31782
5
+ carconnectivity_connectors/skoda/connector.py,sha256=q2tnF8Q99vJUBSSqW8YngdpYvWW5tD69bVoMgQMNyz8,66387
6
+ carconnectivity_connectors/skoda/mqtt_client.py,sha256=oFyuMWchYSdu_St4VzcGsCUzsgUzYdA2_gmzbilgqL8,32105
7
7
  carconnectivity_connectors/skoda/vehicle.py,sha256=H3GRDNimMghFwFi--y9BsgoSK3pMibNf_l6SsDN6gvQ,2759
8
8
  carconnectivity_connectors/skoda/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  carconnectivity_connectors/skoda/auth/auth_util.py,sha256=dGLUbUre0HBsTg_Ii5vW34f8DLrCykYJYCyzEvUBBEE,4434
@@ -12,8 +12,8 @@ carconnectivity_connectors/skoda/auth/openid_session.py,sha256=LusWi2FZZIL3buodG
12
12
  carconnectivity_connectors/skoda/auth/session_manager.py,sha256=Uf1vujuDBYUCAXhYToOsZkgbTtfmY3Qe0ICTfwomBpI,2899
13
13
  carconnectivity_connectors/skoda/auth/skoda_web_session.py,sha256=cjzMkzx473Sh-4RgZAQULeRRcxB1MboddldCVM_y5LE,10640
14
14
  carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
15
- carconnectivity_connector_skoda-0.1a11.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
16
- carconnectivity_connector_skoda-0.1a11.dist-info/METADATA,sha256=tS2ccqTBaAHPxFbNRA7wlbJQPiqLDU8J9h62FQcXvb8,5327
17
- carconnectivity_connector_skoda-0.1a11.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
- carconnectivity_connector_skoda-0.1a11.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
19
- carconnectivity_connector_skoda-0.1a11.dist-info/RECORD,,
15
+ carconnectivity_connector_skoda-0.1a13.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
16
+ carconnectivity_connector_skoda-0.1a13.dist-info/METADATA,sha256=Q4WodCT8EOJN6H_iS6-b0t2Jl6csXoOUnyF8dyZ15as,5327
17
+ carconnectivity_connector_skoda-0.1a13.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
18
+ carconnectivity_connector_skoda-0.1a13.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
19
+ carconnectivity_connector_skoda-0.1a13.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.1a11'
15
+ __version__ = version = '0.1a13'
16
16
  __version_tuple__ = version_tuple = (0, 1)
@@ -15,14 +15,15 @@ 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
24
24
  from carconnectivity.position import Position
25
25
  from carconnectivity.climatization import Climatization
26
+ from carconnectivity.charging_connector import ChargingConnector
26
27
 
27
28
  from carconnectivity_connectors.base.connector import BaseConnector
28
29
  from carconnectivity_connectors.skoda.auth.session_manager import SessionManager, SessionUser, Service
@@ -128,6 +129,8 @@ class Connector(BaseConnector):
128
129
  if not isinstance(session, MySkodaSession):
129
130
  raise AuthenticationError('Could not create session')
130
131
  self.session: MySkodaSession = session
132
+ self.session.retries = 3
133
+ self.session.timeout = 180
131
134
  self.session.refresh()
132
135
 
133
136
  self._elapsed: List[timedelta] = []
@@ -302,7 +305,6 @@ class Connector(BaseConnector):
302
305
  for vin in set(garage.list_vehicle_vins()):
303
306
  vehicle_to_update: Optional[GenericVehicle] = garage.get_vehicle(vin)
304
307
  if vehicle_to_update is not None and isinstance(vehicle_to_update, SkodaVehicle) and vehicle_to_update.is_managed_by_connector(self):
305
- vehicle_to_update = self.fetch_vehicle_status_second_api(vehicle_to_update)
306
308
  vehicle_to_update = self.fetch_driving_range(vehicle_to_update)
307
309
  if vehicle_to_update.capabilities is not None and vehicle_to_update.capabilities.enabled:
308
310
  if vehicle_to_update.capabilities.has_capability('PARKING_POSITION'):
@@ -361,6 +363,7 @@ class Connector(BaseConnector):
361
363
  if 'remainingTimeToFullyChargedInMinutes' in data['status'] and data['status']['remainingTimeToFullyChargedInMinutes'] is not None:
362
364
  remaining_duration: timedelta = timedelta(minutes=data['status']['remainingTimeToFullyChargedInMinutes'])
363
365
  estimated_date_reached: datetime = captured_at + remaining_duration
366
+ estimated_date_reached = estimated_date_reached.replace(second=0, microsecond=0)
364
367
  # pylint: disable-next=protected-access
365
368
  vehicle.charging.estimated_date_reached._set_value(value=estimated_date_reached, measured=captured_at)
366
369
  else:
@@ -525,8 +528,42 @@ class Connector(BaseConnector):
525
528
  log_extra_keys(LOG_API, 'targetTemperature', data['outsideTemperature'], {'carCapturedTimestamp', 'temperatureUnit', 'temperatureValue'})
526
529
  else:
527
530
  vehicle.outside_temperature._set_value(value=None, measured=None, unit=Temperature.UNKNOWN) # pylint: disable=protected-access
531
+ if isinstance(vehicle, SkodaElectricVehicle):
532
+ if 'chargerConnectionState' in data and data['chargerConnectionState'] is not None \
533
+ and vehicle.charging is not None and vehicle.charging.connector is not None:
534
+ if data['chargerConnectionState'] in [item.name for item in ChargingConnector.ChargingConnectorConnectionState]:
535
+ charging_connector_state: ChargingConnector.ChargingConnectorConnectionState = \
536
+ ChargingConnector.ChargingConnectorConnectionState[data['chargerConnectionState']]
537
+ # pylint: disable-next=protected-access
538
+ vehicle.charging.connector.connection_state._set_value(value=charging_connector_state, measured=captured_at)
539
+ else:
540
+ LOG_API.info('Unkown connector state %s not in %s', data['chargerConnectionState'],
541
+ str(ChargingConnector.ChargingConnectorConnectionState))
542
+ # pylint: disable-next=protected-access
543
+ vehicle.charging.connector.connection_state._set_value(value=SkodaCharging.SkodaChargingState.UNKNOWN, measured=captured_at)
544
+ else:
545
+ # pylint: disable-next=protected-access
546
+ vehicle.charging.connector.connection_state._set_value(value=None, measured=captured_at)
547
+ if 'chargerLockState' in data and data['chargerLockState'] is not None \
548
+ and vehicle.charging is not None and vehicle.charging.connector is not None:
549
+ if data['chargerLockState'] in [item.name for item in ChargingConnector.ChargingConnectorLockState]:
550
+ charging_connector_lockstate: ChargingConnector.ChargingConnectorLockState = \
551
+ ChargingConnector.ChargingConnectorLockState[data['chargerLockState']]
552
+ # pylint: disable-next=protected-access
553
+ vehicle.charging.connector.lock_state._set_value(value=charging_connector_lockstate, measured=captured_at)
554
+ else:
555
+ LOG_API.info('Unkown connector lock state %s not in %s', data['chargerLockState'],
556
+ str(ChargingConnector.ChargingConnectorLockState))
557
+ # pylint: disable-next=protected-access
558
+ vehicle.charging.connector.lock_state._set_value(value=SkodaCharging.SkodaChargingState.UNKNOWN, measured=captured_at)
559
+ else:
560
+ # pylint: disable-next=protected-access
561
+ vehicle.charging.connector.lock_state._set_value(value=None, measured=captured_at)
562
+ if 'windowHeatingState' in data and data['windowHeatingState'] is not None:
563
+ pass
528
564
  log_extra_keys(LOG_API, 'air-condition', data, {'carCapturedTimestamp', 'state', 'estimatedDateTimeToReachTargetTemperature'
529
- 'targetTemperature', 'outsideTemperature'})
565
+ 'targetTemperature', 'outsideTemperature', 'chargerConnectionState',
566
+ 'chargerLockState'})
530
567
  return vehicle
531
568
 
532
569
  def fetch_vehicle_details(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
@@ -692,185 +729,186 @@ class Connector(BaseConnector):
692
729
  'secondaryEngineRange'})
693
730
  return vehicle
694
731
 
695
- def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
696
- """
697
- Fetches the status of a vehicle from other Skoda API.
698
-
699
- Args:
700
- vehicle (GenericVehicle): The vehicle object containing the VIN.
701
-
702
- Returns:
703
- None
704
- """
705
- vin = vehicle.vin.value
706
- if vin is None:
707
- raise APIError('VIN is missing')
708
- url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
709
- vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
710
- if vehicle_status_data:
711
- if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
712
- vehicle_status_data = vehicle_status_data['remote']
713
- if vehicle_status_data:
714
- if 'capturedAt' in vehicle_status_data and vehicle_status_data['capturedAt'] is not None:
715
- captured_at: datetime = robust_time_parse(vehicle_status_data['capturedAt'])
716
- else:
717
- raise APIError('Could not fetch vehicle status, capturedAt missing')
718
- if 'mileageInKm' in vehicle_status_data and vehicle_status_data['mileageInKm'] is not None:
719
- vehicle.odometer._set_value(value=vehicle_status_data['mileageInKm'], measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
720
- else:
721
- vehicle.odometer._set_value(value=None, measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
722
- if 'status' in vehicle_status_data and vehicle_status_data['status'] is not None:
723
- if 'open' in vehicle_status_data['status'] and vehicle_status_data['status']['open'] is not None:
724
- if vehicle_status_data['status']['open'] == 'YES':
725
- vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
726
- elif vehicle_status_data['status']['open'] == 'NO':
727
- vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
728
- else:
729
- vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
730
- LOG_API.info('Unknown door open state: %s', vehicle_status_data['status']['open'])
731
- else:
732
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
733
- if 'locked' in vehicle_status_data['status'] and vehicle_status_data['status']['locked'] is not None:
734
- if vehicle_status_data['status']['locked'] == 'YES':
735
- vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
736
- elif vehicle_status_data['status']['locked'] == 'NO':
737
- vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
738
- else:
739
- vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
740
- LOG_API.info('Unknown door lock state: %s', vehicle_status_data['status']['locked'])
741
- else:
742
- vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
743
- else:
744
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
745
- vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
746
- if 'doors' in vehicle_status_data and vehicle_status_data['doors'] is not None:
747
- seen_door_ids: set[str] = set()
748
- for door_status in vehicle_status_data['doors']:
749
- if 'name' in door_status and door_status['name'] is not None:
750
- door_id = door_status['name']
751
- seen_door_ids.add(door_id)
752
- if door_id in vehicle.doors.doors:
753
- door: Doors.Door = vehicle.doors.doors[door_id]
754
- else:
755
- door = Doors.Door(door_id=door_id, doors=vehicle.doors)
756
- vehicle.doors.doors[door_id] = door
757
- if 'status' in door_status and door_status['status'] is not None:
758
- if door_status['status'] == 'OPEN':
759
- door.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
760
- door.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
761
- elif door_status['status'] == 'CLOSED':
762
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
763
- door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
764
- elif door_status['status'] == 'LOCKED':
765
- door.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
766
- door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
767
- elif door_status['status'] == 'UNSUPPORTED':
768
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
769
- door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
770
- else:
771
- LOG_API.info('Unknown door status %s', door_status['status'])
772
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
773
- door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
774
- else:
775
- door.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
776
- door.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
777
- else:
778
- raise APIError('Could not parse door, name missing')
779
- log_extra_keys(LOG_API, 'doors', door_status, {'name', 'status'})
780
- for door_to_remove in set(vehicle.doors.doors) - seen_door_ids:
781
- vehicle.doors.doors[door_to_remove].enabled = False
782
- vehicle.doors.doors.pop(door_to_remove)
783
- log_extra_keys(LOG_API, 'status', vehicle_status_data['status'], {'open', 'locked'})
784
- else:
785
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
786
- vehicle.doors.doors = {}
787
- if 'windows' in vehicle_status_data and vehicle_status_data['windows'] is not None:
788
- seen_window_ids: set[str] = set()
789
- all_windows_closed: bool = True
790
- for window_status in vehicle_status_data['windows']:
791
- if 'name' in window_status and window_status['name'] is not None:
792
- window_id = window_status['name']
793
- seen_window_ids.add(window_id)
794
- if window_id in vehicle.windows.windows:
795
- window: Windows.Window = vehicle.windows.windows[window_id]
796
- else:
797
- window = Windows.Window(window_id=window_id, windows=vehicle.windows)
798
- vehicle.windows.windows[window_id] = window
799
- if 'status' in window_status and window_status['status'] is not None:
800
- if window_status['status'] == 'OPEN':
801
- all_windows_closed = False
802
- window.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
803
- elif window_status['status'] == 'CLOSED':
804
- window.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
805
- elif window_status['status'] == 'UNSUPPORTED':
806
- window.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
807
- elif window_status['status'] == 'INVALID':
808
- window.open_state._set_value(Windows.OpenState.INVALID, measured=captured_at) # pylint: disable=protected-access
809
- else:
810
- LOG_API.info('Unknown window status %s', window_status['status'])
811
- window.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
812
- else:
813
- window.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
814
- else:
815
- raise APIError('Could not parse window, name missing')
816
- log_extra_keys(LOG_API, 'doors', window_status, {'name', 'status'})
817
- for window_to_remove in set(vehicle.windows.windows) - seen_window_ids:
818
- vehicle.windows.windows[window_to_remove].enabled = False
819
- vehicle.windows.windows.pop(window_to_remove)
820
- if all_windows_closed:
821
- vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
822
- else:
823
- vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
824
- else:
825
- vehicle.windows.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
826
- vehicle.windows.windows = {}
827
- if 'lights' in vehicle_status_data and vehicle_status_data['lights'] is not None:
828
- seen_light_ids: set[str] = set()
829
- if 'overallStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['overallStatus'] is not None:
830
- if vehicle_status_data['lights']['overallStatus'] == 'ON':
831
- vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
832
- elif vehicle_status_data['lights']['overallStatus'] == 'OFF':
833
- vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
834
- elif vehicle_status_data['lights']['overallStatus'] == 'INVALID':
835
- vehicle.lights.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
836
- else:
837
- LOG_API.info('Unknown light status %s', vehicle_status_data['lights']['overallStatus'])
838
- vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
839
- else:
840
- vehicle.lights.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
841
- if 'lightsStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['lightsStatus'] is not None:
842
- for light_status in vehicle_status_data['lights']['lightsStatus']:
843
- if 'name' in light_status and light_status['name'] is not None:
844
- light_id: str = light_status['name']
845
- seen_light_ids.add(light_id)
846
- if light_id in vehicle.lights.lights:
847
- light: Lights.Light = vehicle.lights.lights[light_id]
848
- else:
849
- light = Lights.Light(light_id=light_id, lights=vehicle.lights)
850
- vehicle.lights.lights[light_id] = light
851
- if 'status' in light_status and light_status['status'] is not None:
852
- if light_status['status'] == 'ON':
853
- light.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
854
- elif light_status['status'] == 'OFF':
855
- light.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
856
- elif light_status['status'] == 'INVALID':
857
- light.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
858
- else:
859
- LOG_API.info('Unknown light status %s', light_status['status'])
860
- light.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
861
- else:
862
- light.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
863
- else:
864
- raise APIError('Could not parse light, name missing')
865
- log_extra_keys(LOG_API, 'lights', light_status, {'name', 'status'})
866
- for light_to_remove in set(vehicle.lights.lights) - seen_light_ids:
867
- vehicle.lights.lights[light_to_remove].enabled = False
868
- vehicle.lights.lights.pop(light_to_remove)
869
- else:
870
- vehicle.lights.lights = {}
871
- log_extra_keys(LOG_API, 'lights', vehicle_status_data['lights'], {'overallStatus', 'lightsStatus'})
872
- log_extra_keys(LOG_API, 'vehicles', vehicle_status_data, {'capturedAt', 'mileageInKm', 'status', 'doors', 'windows', 'lights'})
873
- return vehicle
732
+ # def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
733
+ # """
734
+ # Fetches the status of a vehicle from other Skoda API.
735
+ #
736
+ # Args:
737
+ # vehicle (GenericVehicle): The vehicle object containing the VIN.
738
+ #
739
+ # Returns:
740
+ # None
741
+ # """
742
+ # vin = vehicle.vin.value
743
+ # if vin is None:
744
+ # raise APIError('VIN is missing')
745
+ # url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
746
+ # vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
747
+ # if vehicle_status_data:
748
+ # if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
749
+ # vehicle_status_data = vehicle_status_data['remote']
750
+ # if vehicle_status_data:
751
+ # if 'capturedAt' in vehicle_status_data and vehicle_status_data['capturedAt'] is not None:
752
+ # captured_at: datetime = robust_time_parse(vehicle_status_data['capturedAt'])
753
+ # else:
754
+ # raise APIError('Could not fetch vehicle status, capturedAt missing')
755
+ # if 'mileageInKm' in vehicle_status_data and vehicle_status_data['mileageInKm'] is not None:
756
+ # # pylint: disable-next=protected-access
757
+ # vehicle.odometer._set_value(value=vehicle_status_data['mileageInKm'], measured=captured_at, unit=Length.KM)
758
+ # else:
759
+ # vehicle.odometer._set_value(value=None, measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
760
+ # if 'status' in vehicle_status_data and vehicle_status_data['status'] is not None:
761
+ # if 'open' in vehicle_status_data['status'] and vehicle_status_data['status']['open'] is not None:
762
+ # if vehicle_status_data['status']['open'] == 'YES':
763
+ # vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
764
+ # elif vehicle_status_data['status']['open'] == 'NO':
765
+ # vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
766
+ # else:
767
+ # vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
768
+ # LOG_API.info('Unknown door open state: %s', vehicle_status_data['status']['open'])
769
+ # else:
770
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
771
+ # if 'locked' in vehicle_status_data['status'] and vehicle_status_data['status']['locked'] is not None:
772
+ # if vehicle_status_data['status']['locked'] == 'YES':
773
+ # vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
774
+ # elif vehicle_status_data['status']['locked'] == 'NO':
775
+ # vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
776
+ # else:
777
+ # vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
778
+ # LOG_API.info('Unknown door lock state: %s', vehicle_status_data['status']['locked'])
779
+ # else:
780
+ # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
781
+ # else:
782
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
783
+ # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
784
+ # if 'doors' in vehicle_status_data and vehicle_status_data['doors'] is not None:
785
+ # seen_door_ids: set[str] = set()
786
+ # for door_status in vehicle_status_data['doors']:
787
+ # if 'name' in door_status and door_status['name'] is not None:
788
+ # door_id = door_status['name']
789
+ # seen_door_ids.add(door_id)
790
+ # if door_id in vehicle.doors.doors:
791
+ # door: Doors.Door = vehicle.doors.doors[door_id]
792
+ # else:
793
+ # door = Doors.Door(door_id=door_id, doors=vehicle.doors)
794
+ # vehicle.doors.doors[door_id] = door
795
+ # if 'status' in door_status and door_status['status'] is not None:
796
+ # if door_status['status'] == 'OPEN':
797
+ # door.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
798
+ # door.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
799
+ # elif door_status['status'] == 'CLOSED':
800
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
801
+ # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
802
+ # elif door_status['status'] == 'LOCKED':
803
+ # door.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
804
+ # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
805
+ # elif door_status['status'] == 'UNSUPPORTED':
806
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
807
+ # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
808
+ # else:
809
+ # LOG_API.info('Unknown door status %s', door_status['status'])
810
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
811
+ # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
812
+ # else:
813
+ # door.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
814
+ # door.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
815
+ # else:
816
+ # raise APIError('Could not parse door, name missing')
817
+ # log_extra_keys(LOG_API, 'doors', door_status, {'name', 'status'})
818
+ # for door_to_remove in set(vehicle.doors.doors) - seen_door_ids:
819
+ # vehicle.doors.doors[door_to_remove].enabled = False
820
+ # vehicle.doors.doors.pop(door_to_remove)
821
+ # log_extra_keys(LOG_API, 'status', vehicle_status_data['status'], {'open', 'locked'})
822
+ # else:
823
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
824
+ # vehicle.doors.doors = {}
825
+ # if 'windows' in vehicle_status_data and vehicle_status_data['windows'] is not None:
826
+ # seen_window_ids: set[str] = set()
827
+ # all_windows_closed: bool = True
828
+ # for window_status in vehicle_status_data['windows']:
829
+ # if 'name' in window_status and window_status['name'] is not None:
830
+ # window_id = window_status['name']
831
+ # seen_window_ids.add(window_id)
832
+ # if window_id in vehicle.windows.windows:
833
+ # window: Windows.Window = vehicle.windows.windows[window_id]
834
+ # else:
835
+ # window = Windows.Window(window_id=window_id, windows=vehicle.windows)
836
+ # vehicle.windows.windows[window_id] = window
837
+ # if 'status' in window_status and window_status['status'] is not None:
838
+ # if window_status['status'] == 'OPEN':
839
+ # all_windows_closed = False
840
+ # window.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
841
+ # elif window_status['status'] == 'CLOSED':
842
+ # window.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
843
+ # elif window_status['status'] == 'UNSUPPORTED':
844
+ # window.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
845
+ # elif window_status['status'] == 'INVALID':
846
+ # window.open_state._set_value(Windows.OpenState.INVALID, measured=captured_at) # pylint: disable=protected-access
847
+ # else:
848
+ # LOG_API.info('Unknown window status %s', window_status['status'])
849
+ # window.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
850
+ # else:
851
+ # window.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
852
+ # else:
853
+ # raise APIError('Could not parse window, name missing')
854
+ # log_extra_keys(LOG_API, 'doors', window_status, {'name', 'status'})
855
+ # for window_to_remove in set(vehicle.windows.windows) - seen_window_ids:
856
+ # vehicle.windows.windows[window_to_remove].enabled = False
857
+ # vehicle.windows.windows.pop(window_to_remove)
858
+ # if all_windows_closed:
859
+ # vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
860
+ # else:
861
+ # vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
862
+ # else:
863
+ # vehicle.windows.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
864
+ # vehicle.windows.windows = {}
865
+ # if 'lights' in vehicle_status_data and vehicle_status_data['lights'] is not None:
866
+ # seen_light_ids: set[str] = set()
867
+ # if 'overallStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['overallStatus'] is not None:
868
+ # if vehicle_status_data['lights']['overallStatus'] == 'ON':
869
+ # vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
870
+ # elif vehicle_status_data['lights']['overallStatus'] == 'OFF':
871
+ # vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
872
+ # elif vehicle_status_data['lights']['overallStatus'] == 'INVALID':
873
+ # vehicle.lights.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
874
+ # else:
875
+ # LOG_API.info('Unknown light status %s', vehicle_status_data['lights']['overallStatus'])
876
+ # vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
877
+ # else:
878
+ # vehicle.lights.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
879
+ # if 'lightsStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['lightsStatus'] is not None:
880
+ # for light_status in vehicle_status_data['lights']['lightsStatus']:
881
+ # if 'name' in light_status and light_status['name'] is not None:
882
+ # light_id: str = light_status['name']
883
+ # seen_light_ids.add(light_id)
884
+ # if light_id in vehicle.lights.lights:
885
+ # light: Lights.Light = vehicle.lights.lights[light_id]
886
+ # else:
887
+ # light = Lights.Light(light_id=light_id, lights=vehicle.lights)
888
+ # vehicle.lights.lights[light_id] = light
889
+ # if 'status' in light_status and light_status['status'] is not None:
890
+ # if light_status['status'] == 'ON':
891
+ # light.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
892
+ # elif light_status['status'] == 'OFF':
893
+ # light.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
894
+ # elif light_status['status'] == 'INVALID':
895
+ # light.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
896
+ # else:
897
+ # LOG_API.info('Unknown light status %s', light_status['status'])
898
+ # light.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
899
+ # else:
900
+ # light.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
901
+ # else:
902
+ # raise APIError('Could not parse light, name missing')
903
+ # log_extra_keys(LOG_API, 'lights', light_status, {'name', 'status'})
904
+ # for light_to_remove in set(vehicle.lights.lights) - seen_light_ids:
905
+ # vehicle.lights.lights[light_to_remove].enabled = False
906
+ # vehicle.lights.lights.pop(light_to_remove)
907
+ # else:
908
+ # vehicle.lights.lights = {}
909
+ # log_extra_keys(LOG_API, 'lights', vehicle_status_data['lights'], {'overallStatus', 'lightsStatus'})
910
+ # log_extra_keys(LOG_API, 'vehicles', vehicle_status_data, {'capturedAt', 'mileageInKm', 'status', 'doors', 'windows', 'lights'})
911
+ # return vehicle
874
912
 
875
913
  def _record_elapsed(self, elapsed: timedelta) -> None:
876
914
  """
@@ -20,6 +20,7 @@ from carconnectivity.vehicle import GenericVehicle
20
20
  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
+ from carconnectivity.climatization import Climatization
23
24
 
24
25
  from carconnectivity_connectors.skoda.vehicle import SkodaVehicle, SkodaElectricVehicle
25
26
  from carconnectivity_connectors.skoda.charging import SkodaCharging, mapping_skoda_charging_state
@@ -492,6 +493,7 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
492
493
  try:
493
494
  remaining_duration: Optional[timedelta] = timedelta(minutes=int(data['data']['timeToFinish']))
494
495
  estimated_date_reached: Optional[datetime] = measured_at + remaining_duration
496
+ estimated_date_reached = estimated_date_reached.replace(second=0, microsecond=0)
495
497
  except ValueError:
496
498
  estimated_date_reached: Optional[datetime] = None
497
499
  # pylint: disable-next=protected-access
@@ -513,6 +515,14 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
513
515
  self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
514
516
  except CarConnectivityError as e:
515
517
  LOG.error('Error while fetching charging: %s', e)
518
+ elif 'name' in data and data['name'] == 'climatisation-completed':
519
+ if 'data' in data and data['data'] is not None:
520
+ vehicle: Optional[GenericVehicle] = self._skoda_connector.car_connectivity.garage.get_vehicle(vin)
521
+ if vehicle is not None and vehicle.climatization is not None:
522
+ # pylint: disable-next=protected-access
523
+ vehicle.climatization.state._set_value(value=Climatization.ClimatizationState.OFF, measured=measured_at)
524
+ # pylint: disable-next=protected-access
525
+ vehicle.climatization.estimated_date_reached._set_value(value=measured_at, measured=measured_at)
516
526
  LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
517
527
  service_event, vin, user_id, msg.payload)
518
528
  return
@@ -545,14 +555,6 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
545
555
  self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
546
556
  except CarConnectivityError as e:
547
557
  LOG.error('Error while fetching air conditioning: %s', e)
548
- try:
549
- self._skoda_connector.fetch_vehicle_status_second_api(vehicle, no_cache=True)
550
- except CarConnectivityError as e:
551
- LOG.error('Error while fetching status second API: %s', e)
552
- try:
553
- self._skoda_connector.fetch_driving_range(vehicle, no_cache=True)
554
- except CarConnectivityError as e:
555
- LOG.error('Error while fetching driving range: %s', e)
556
558
 
557
559
  if vin in self.delayed_access_function_timers:
558
560
  self.delayed_access_function_timers[vin].cancel()