carconnectivity-connector-skoda 0.1a12__tar.gz → 0.1a14__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 (35) hide show
  1. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/PKG-INFO +1 -1
  2. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connector_skoda.egg-info/PKG-INFO +1 -1
  3. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/_version.py +1 -1
  4. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/connector.py +255 -186
  5. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/mqtt_client.py +9 -4
  6. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.flake8 +0 -0
  7. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  8. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  9. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/dependabot.yml +0 -0
  10. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/workflows/build.yml +0 -0
  11. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/workflows/build_and_publish.yml +0 -0
  12. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.github/workflows/codeql-analysis.yml +0 -0
  13. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/.gitignore +0 -0
  14. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/LICENSE +0 -0
  15. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/Makefile +0 -0
  16. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/README.md +0 -0
  17. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/doc/Config.md +0 -0
  18. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/pyproject.toml +0 -0
  19. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/setup.cfg +0 -0
  20. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/setup_requirements.txt +0 -0
  21. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connector_skoda.egg-info/SOURCES.txt +0 -0
  22. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connector_skoda.egg-info/dependency_links.txt +0 -0
  23. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connector_skoda.egg-info/requires.txt +0 -0
  24. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connector_skoda.egg-info/top_level.txt +0 -0
  25. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/__init__.py +0 -0
  26. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/__init__.py +0 -0
  27. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/auth_util.py +0 -0
  28. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py +0 -0
  29. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/my_skoda_session.py +0 -0
  30. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/openid_session.py +0 -0
  31. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/session_manager.py +0 -0
  32. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/auth/skoda_web_session.py +0 -0
  33. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/capability.py +0 -0
  34. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/src/carconnectivity_connectors/skoda/charging.py +0 -0
  35. {carconnectivity_connector_skoda-0.1a12 → carconnectivity_connector_skoda-0.1a14}/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.1a12
3
+ Version: 0.1a14
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.1a12
3
+ Version: 0.1a14
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.1a12'
15
+ __version__ = version = '0.1a14'
16
16
  __version_tuple__ = version_tuple = (0, 1)
@@ -1,4 +1,4 @@
1
- """Module implements the connector to interact with the Skoda API."""
1
+ """Module implements the connector to interact with the Skoda API.""" # pylint: disable=too-many-lines
2
2
  from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
@@ -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] = []
@@ -177,6 +180,9 @@ class Connector(BaseConnector):
177
180
  except RetrievalError as err:
178
181
  LOG.error('Retrieval error during update (%s). Will try again after configured interval of %ss', str(err), interval)
179
182
  self._stop_event.wait(interval)
183
+ except APIError as err:
184
+ LOG.error('API error during update (%s). Will try again after configured interval of %ss', str(err), interval)
185
+ self._stop_event.wait(interval)
180
186
  except APICompatibilityError as err:
181
187
  LOG.error('API compatability error during update (%s). Will try again after configured interval of %ss', str(err), interval)
182
188
  self._stop_event.wait(interval)
@@ -302,7 +308,6 @@ class Connector(BaseConnector):
302
308
  for vin in set(garage.list_vehicle_vins()):
303
309
  vehicle_to_update: Optional[GenericVehicle] = garage.get_vehicle(vin)
304
310
  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
311
  vehicle_to_update = self.fetch_driving_range(vehicle_to_update)
307
312
  if vehicle_to_update.capabilities is not None and vehicle_to_update.capabilities.enabled:
308
313
  if vehicle_to_update.capabilities.has_capability('PARKING_POSITION'):
@@ -366,10 +371,39 @@ class Connector(BaseConnector):
366
371
  vehicle.charging.estimated_date_reached._set_value(value=estimated_date_reached, measured=captured_at)
367
372
  else:
368
373
  vehicle.charging.estimated_date_reached._set_value(None, measured=captured_at) # pylint: disable=protected-access
374
+ if 'chargeType' in data['status'] and data['status']['chargeType'] is not None:
375
+ if data['status']['chargeType'] in [item.name for item in Charging.ChargingType]:
376
+ charge_type: Charging.ChargingType = Charging.ChargingType[data['status']['chargeType']]
377
+ else:
378
+ LOG_API.info('Unknown charge type %s not in %s', data['status']['chargeType'], str(Charging.ChargingType))
379
+ charge_type = Charging.ChargingType.UNKNOWN
380
+ # pylint: disable-next=protected-access
381
+ vehicle.charging.type._set_value(value=charge_type, measured=captured_at)
382
+ else:
383
+ # pylint: disable-next=protected-access
384
+ vehicle.charging.type._set_value(None, measured=captured_at)
385
+ if 'battery' in data['status'] and data['status']['battery'] is not None:
386
+ for drive in vehicle.drives.drives.values():
387
+ # Assume first electric drive is the right one
388
+ if isinstance(drive, ElectricDrive):
389
+ if 'remainingCruisingRangeInMeters' in data['status']['battery'] \
390
+ and data['status']['battery']['remainingCruisingRangeInMeters'] is not None:
391
+ cruising_range_in_km: float = data['status']['battery']['remainingCruisingRangeInMeters'] / 1000
392
+ # pylint: disable-next=protected-access
393
+ drive.range._set_value(value=cruising_range_in_km, measured=captured_at, unit=Length.KM)
394
+ if 'stateOfChargeInPercent' in data['status']['battery'] \
395
+ and data['status']['battery']['stateOfChargeInPercent'] is not None:
396
+ # pylint: disable-next=protected-access
397
+ drive.level._set_value(value=data['status']['battery']['stateOfChargeInPercent'], measured=captured_at)
398
+ log_extra_keys(LOG_API, 'status', data['status']['battery'], {'remainingCruisingRangeInMeters',
399
+ 'stateOfChargeInPercent'})
400
+ break
369
401
  log_extra_keys(LOG_API, 'status', data['status'], {'chargingRateInKilometersPerHour',
370
402
  'chargePowerInKw',
371
403
  'remainingTimeToFullyChargedInMinutes',
372
- 'state'})
404
+ 'state',
405
+ 'chargeType',
406
+ 'battery'})
373
407
  log_extra_keys(LOG_API, 'charging data', data, {'carCapturedTimestamp', 'status'})
374
408
  return vehicle
375
409
 
@@ -526,8 +560,42 @@ class Connector(BaseConnector):
526
560
  log_extra_keys(LOG_API, 'targetTemperature', data['outsideTemperature'], {'carCapturedTimestamp', 'temperatureUnit', 'temperatureValue'})
527
561
  else:
528
562
  vehicle.outside_temperature._set_value(value=None, measured=None, unit=Temperature.UNKNOWN) # pylint: disable=protected-access
563
+ if isinstance(vehicle, SkodaElectricVehicle):
564
+ if 'chargerConnectionState' in data and data['chargerConnectionState'] is not None \
565
+ and vehicle.charging is not None and vehicle.charging.connector is not None:
566
+ if data['chargerConnectionState'] in [item.name for item in ChargingConnector.ChargingConnectorConnectionState]:
567
+ charging_connector_state: ChargingConnector.ChargingConnectorConnectionState = \
568
+ ChargingConnector.ChargingConnectorConnectionState[data['chargerConnectionState']]
569
+ # pylint: disable-next=protected-access
570
+ vehicle.charging.connector.connection_state._set_value(value=charging_connector_state, measured=captured_at)
571
+ else:
572
+ LOG_API.info('Unkown connector state %s not in %s', data['chargerConnectionState'],
573
+ str(ChargingConnector.ChargingConnectorConnectionState))
574
+ # pylint: disable-next=protected-access
575
+ vehicle.charging.connector.connection_state._set_value(value=SkodaCharging.SkodaChargingState.UNKNOWN, measured=captured_at)
576
+ else:
577
+ # pylint: disable-next=protected-access
578
+ vehicle.charging.connector.connection_state._set_value(value=None, measured=captured_at)
579
+ if 'chargerLockState' in data and data['chargerLockState'] is not None \
580
+ and vehicle.charging is not None and vehicle.charging.connector is not None:
581
+ if data['chargerLockState'] in [item.name for item in ChargingConnector.ChargingConnectorLockState]:
582
+ charging_connector_lockstate: ChargingConnector.ChargingConnectorLockState = \
583
+ ChargingConnector.ChargingConnectorLockState[data['chargerLockState']]
584
+ # pylint: disable-next=protected-access
585
+ vehicle.charging.connector.lock_state._set_value(value=charging_connector_lockstate, measured=captured_at)
586
+ else:
587
+ LOG_API.info('Unkown connector lock state %s not in %s', data['chargerLockState'],
588
+ str(ChargingConnector.ChargingConnectorLockState))
589
+ # pylint: disable-next=protected-access
590
+ vehicle.charging.connector.lock_state._set_value(value=SkodaCharging.SkodaChargingState.UNKNOWN, measured=captured_at)
591
+ else:
592
+ # pylint: disable-next=protected-access
593
+ vehicle.charging.connector.lock_state._set_value(value=None, measured=captured_at)
594
+ if 'windowHeatingState' in data and data['windowHeatingState'] is not None:
595
+ pass
529
596
  log_extra_keys(LOG_API, 'air-condition', data, {'carCapturedTimestamp', 'state', 'estimatedDateTimeToReachTargetTemperature'
530
- 'targetTemperature', 'outsideTemperature'})
597
+ 'targetTemperature', 'outsideTemperature', 'chargerConnectionState',
598
+ 'chargerLockState'})
531
599
  return vehicle
532
600
 
533
601
  def fetch_vehicle_details(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
@@ -693,185 +761,186 @@ class Connector(BaseConnector):
693
761
  'secondaryEngineRange'})
694
762
  return vehicle
695
763
 
696
- def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
697
- """
698
- Fetches the status of a vehicle from other Skoda API.
699
-
700
- Args:
701
- vehicle (GenericVehicle): The vehicle object containing the VIN.
702
-
703
- Returns:
704
- None
705
- """
706
- vin = vehicle.vin.value
707
- if vin is None:
708
- raise APIError('VIN is missing')
709
- url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
710
- vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
711
- if vehicle_status_data:
712
- if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
713
- vehicle_status_data = vehicle_status_data['remote']
714
- if vehicle_status_data:
715
- if 'capturedAt' in vehicle_status_data and vehicle_status_data['capturedAt'] is not None:
716
- captured_at: datetime = robust_time_parse(vehicle_status_data['capturedAt'])
717
- else:
718
- raise APIError('Could not fetch vehicle status, capturedAt missing')
719
- if 'mileageInKm' in vehicle_status_data and vehicle_status_data['mileageInKm'] is not None:
720
- vehicle.odometer._set_value(value=vehicle_status_data['mileageInKm'], measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
721
- else:
722
- vehicle.odometer._set_value(value=None, measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
723
- if 'status' in vehicle_status_data and vehicle_status_data['status'] is not None:
724
- if 'open' in vehicle_status_data['status'] and vehicle_status_data['status']['open'] is not None:
725
- if vehicle_status_data['status']['open'] == 'YES':
726
- vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
727
- elif vehicle_status_data['status']['open'] == 'NO':
728
- vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
729
- else:
730
- vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
731
- LOG_API.info('Unknown door open state: %s', vehicle_status_data['status']['open'])
732
- else:
733
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
734
- if 'locked' in vehicle_status_data['status'] and vehicle_status_data['status']['locked'] is not None:
735
- if vehicle_status_data['status']['locked'] == 'YES':
736
- vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
737
- elif vehicle_status_data['status']['locked'] == 'NO':
738
- vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
739
- else:
740
- vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
741
- LOG_API.info('Unknown door lock state: %s', vehicle_status_data['status']['locked'])
742
- else:
743
- vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
744
- else:
745
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
746
- vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
747
- if 'doors' in vehicle_status_data and vehicle_status_data['doors'] is not None:
748
- seen_door_ids: set[str] = set()
749
- for door_status in vehicle_status_data['doors']:
750
- if 'name' in door_status and door_status['name'] is not None:
751
- door_id = door_status['name']
752
- seen_door_ids.add(door_id)
753
- if door_id in vehicle.doors.doors:
754
- door: Doors.Door = vehicle.doors.doors[door_id]
755
- else:
756
- door = Doors.Door(door_id=door_id, doors=vehicle.doors)
757
- vehicle.doors.doors[door_id] = door
758
- if 'status' in door_status and door_status['status'] is not None:
759
- if door_status['status'] == 'OPEN':
760
- door.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
761
- door.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
762
- elif door_status['status'] == 'CLOSED':
763
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
764
- door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
765
- elif door_status['status'] == 'LOCKED':
766
- door.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
767
- door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
768
- elif door_status['status'] == 'UNSUPPORTED':
769
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
770
- door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
771
- else:
772
- LOG_API.info('Unknown door status %s', door_status['status'])
773
- door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
774
- door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
775
- else:
776
- door.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
777
- door.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
778
- else:
779
- raise APIError('Could not parse door, name missing')
780
- log_extra_keys(LOG_API, 'doors', door_status, {'name', 'status'})
781
- for door_to_remove in set(vehicle.doors.doors) - seen_door_ids:
782
- vehicle.doors.doors[door_to_remove].enabled = False
783
- vehicle.doors.doors.pop(door_to_remove)
784
- log_extra_keys(LOG_API, 'status', vehicle_status_data['status'], {'open', 'locked'})
785
- else:
786
- vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
787
- vehicle.doors.doors = {}
788
- if 'windows' in vehicle_status_data and vehicle_status_data['windows'] is not None:
789
- seen_window_ids: set[str] = set()
790
- all_windows_closed: bool = True
791
- for window_status in vehicle_status_data['windows']:
792
- if 'name' in window_status and window_status['name'] is not None:
793
- window_id = window_status['name']
794
- seen_window_ids.add(window_id)
795
- if window_id in vehicle.windows.windows:
796
- window: Windows.Window = vehicle.windows.windows[window_id]
797
- else:
798
- window = Windows.Window(window_id=window_id, windows=vehicle.windows)
799
- vehicle.windows.windows[window_id] = window
800
- if 'status' in window_status and window_status['status'] is not None:
801
- if window_status['status'] == 'OPEN':
802
- all_windows_closed = False
803
- window.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
804
- elif window_status['status'] == 'CLOSED':
805
- window.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
806
- elif window_status['status'] == 'UNSUPPORTED':
807
- window.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
808
- elif window_status['status'] == 'INVALID':
809
- window.open_state._set_value(Windows.OpenState.INVALID, measured=captured_at) # pylint: disable=protected-access
810
- else:
811
- LOG_API.info('Unknown window status %s', window_status['status'])
812
- window.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
813
- else:
814
- window.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
815
- else:
816
- raise APIError('Could not parse window, name missing')
817
- log_extra_keys(LOG_API, 'doors', window_status, {'name', 'status'})
818
- for window_to_remove in set(vehicle.windows.windows) - seen_window_ids:
819
- vehicle.windows.windows[window_to_remove].enabled = False
820
- vehicle.windows.windows.pop(window_to_remove)
821
- if all_windows_closed:
822
- vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
823
- else:
824
- vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
825
- else:
826
- vehicle.windows.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
827
- vehicle.windows.windows = {}
828
- if 'lights' in vehicle_status_data and vehicle_status_data['lights'] is not None:
829
- seen_light_ids: set[str] = set()
830
- if 'overallStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['overallStatus'] is not None:
831
- if vehicle_status_data['lights']['overallStatus'] == 'ON':
832
- vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
833
- elif vehicle_status_data['lights']['overallStatus'] == 'OFF':
834
- vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
835
- elif vehicle_status_data['lights']['overallStatus'] == 'INVALID':
836
- vehicle.lights.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
837
- else:
838
- LOG_API.info('Unknown light status %s', vehicle_status_data['lights']['overallStatus'])
839
- vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
840
- else:
841
- vehicle.lights.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
842
- if 'lightsStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['lightsStatus'] is not None:
843
- for light_status in vehicle_status_data['lights']['lightsStatus']:
844
- if 'name' in light_status and light_status['name'] is not None:
845
- light_id: str = light_status['name']
846
- seen_light_ids.add(light_id)
847
- if light_id in vehicle.lights.lights:
848
- light: Lights.Light = vehicle.lights.lights[light_id]
849
- else:
850
- light = Lights.Light(light_id=light_id, lights=vehicle.lights)
851
- vehicle.lights.lights[light_id] = light
852
- if 'status' in light_status and light_status['status'] is not None:
853
- if light_status['status'] == 'ON':
854
- light.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
855
- elif light_status['status'] == 'OFF':
856
- light.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
857
- elif light_status['status'] == 'INVALID':
858
- light.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
859
- else:
860
- LOG_API.info('Unknown light status %s', light_status['status'])
861
- light.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
862
- else:
863
- light.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
864
- else:
865
- raise APIError('Could not parse light, name missing')
866
- log_extra_keys(LOG_API, 'lights', light_status, {'name', 'status'})
867
- for light_to_remove in set(vehicle.lights.lights) - seen_light_ids:
868
- vehicle.lights.lights[light_to_remove].enabled = False
869
- vehicle.lights.lights.pop(light_to_remove)
870
- else:
871
- vehicle.lights.lights = {}
872
- log_extra_keys(LOG_API, 'lights', vehicle_status_data['lights'], {'overallStatus', 'lightsStatus'})
873
- log_extra_keys(LOG_API, 'vehicles', vehicle_status_data, {'capturedAt', 'mileageInKm', 'status', 'doors', 'windows', 'lights'})
874
- return vehicle
764
+ # def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
765
+ # """
766
+ # Fetches the status of a vehicle from other Skoda API.
767
+ #
768
+ # Args:
769
+ # vehicle (GenericVehicle): The vehicle object containing the VIN.
770
+ #
771
+ # Returns:
772
+ # None
773
+ # """
774
+ # vin = vehicle.vin.value
775
+ # if vin is None:
776
+ # raise APIError('VIN is missing')
777
+ # url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
778
+ # vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
779
+ # if vehicle_status_data:
780
+ # if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
781
+ # vehicle_status_data = vehicle_status_data['remote']
782
+ # if vehicle_status_data:
783
+ # if 'capturedAt' in vehicle_status_data and vehicle_status_data['capturedAt'] is not None:
784
+ # captured_at: datetime = robust_time_parse(vehicle_status_data['capturedAt'])
785
+ # else:
786
+ # raise APIError('Could not fetch vehicle status, capturedAt missing')
787
+ # if 'mileageInKm' in vehicle_status_data and vehicle_status_data['mileageInKm'] is not None:
788
+ # # pylint: disable-next=protected-access
789
+ # vehicle.odometer._set_value(value=vehicle_status_data['mileageInKm'], measured=captured_at, unit=Length.KM)
790
+ # else:
791
+ # vehicle.odometer._set_value(value=None, measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
792
+ # if 'status' in vehicle_status_data and vehicle_status_data['status'] is not None:
793
+ # if 'open' in vehicle_status_data['status'] and vehicle_status_data['status']['open'] is not None:
794
+ # if vehicle_status_data['status']['open'] == 'YES':
795
+ # vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
796
+ # elif vehicle_status_data['status']['open'] == 'NO':
797
+ # vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
798
+ # else:
799
+ # vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
800
+ # LOG_API.info('Unknown door open state: %s', vehicle_status_data['status']['open'])
801
+ # else:
802
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
803
+ # if 'locked' in vehicle_status_data['status'] and vehicle_status_data['status']['locked'] is not None:
804
+ # if vehicle_status_data['status']['locked'] == 'YES':
805
+ # vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
806
+ # elif vehicle_status_data['status']['locked'] == 'NO':
807
+ # vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
808
+ # else:
809
+ # vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
810
+ # LOG_API.info('Unknown door lock state: %s', vehicle_status_data['status']['locked'])
811
+ # else:
812
+ # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
813
+ # else:
814
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
815
+ # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
816
+ # if 'doors' in vehicle_status_data and vehicle_status_data['doors'] is not None:
817
+ # seen_door_ids: set[str] = set()
818
+ # for door_status in vehicle_status_data['doors']:
819
+ # if 'name' in door_status and door_status['name'] is not None:
820
+ # door_id = door_status['name']
821
+ # seen_door_ids.add(door_id)
822
+ # if door_id in vehicle.doors.doors:
823
+ # door: Doors.Door = vehicle.doors.doors[door_id]
824
+ # else:
825
+ # door = Doors.Door(door_id=door_id, doors=vehicle.doors)
826
+ # vehicle.doors.doors[door_id] = door
827
+ # if 'status' in door_status and door_status['status'] is not None:
828
+ # if door_status['status'] == 'OPEN':
829
+ # door.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
830
+ # door.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
831
+ # elif door_status['status'] == 'CLOSED':
832
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
833
+ # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
834
+ # elif door_status['status'] == 'LOCKED':
835
+ # door.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
836
+ # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
837
+ # elif door_status['status'] == 'UNSUPPORTED':
838
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
839
+ # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
840
+ # else:
841
+ # LOG_API.info('Unknown door status %s', door_status['status'])
842
+ # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
843
+ # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
844
+ # else:
845
+ # door.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
846
+ # door.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
847
+ # else:
848
+ # raise APIError('Could not parse door, name missing')
849
+ # log_extra_keys(LOG_API, 'doors', door_status, {'name', 'status'})
850
+ # for door_to_remove in set(vehicle.doors.doors) - seen_door_ids:
851
+ # vehicle.doors.doors[door_to_remove].enabled = False
852
+ # vehicle.doors.doors.pop(door_to_remove)
853
+ # log_extra_keys(LOG_API, 'status', vehicle_status_data['status'], {'open', 'locked'})
854
+ # else:
855
+ # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
856
+ # vehicle.doors.doors = {}
857
+ # if 'windows' in vehicle_status_data and vehicle_status_data['windows'] is not None:
858
+ # seen_window_ids: set[str] = set()
859
+ # all_windows_closed: bool = True
860
+ # for window_status in vehicle_status_data['windows']:
861
+ # if 'name' in window_status and window_status['name'] is not None:
862
+ # window_id = window_status['name']
863
+ # seen_window_ids.add(window_id)
864
+ # if window_id in vehicle.windows.windows:
865
+ # window: Windows.Window = vehicle.windows.windows[window_id]
866
+ # else:
867
+ # window = Windows.Window(window_id=window_id, windows=vehicle.windows)
868
+ # vehicle.windows.windows[window_id] = window
869
+ # if 'status' in window_status and window_status['status'] is not None:
870
+ # if window_status['status'] == 'OPEN':
871
+ # all_windows_closed = False
872
+ # window.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
873
+ # elif window_status['status'] == 'CLOSED':
874
+ # window.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
875
+ # elif window_status['status'] == 'UNSUPPORTED':
876
+ # window.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
877
+ # elif window_status['status'] == 'INVALID':
878
+ # window.open_state._set_value(Windows.OpenState.INVALID, measured=captured_at) # pylint: disable=protected-access
879
+ # else:
880
+ # LOG_API.info('Unknown window status %s', window_status['status'])
881
+ # window.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
882
+ # else:
883
+ # window.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
884
+ # else:
885
+ # raise APIError('Could not parse window, name missing')
886
+ # log_extra_keys(LOG_API, 'doors', window_status, {'name', 'status'})
887
+ # for window_to_remove in set(vehicle.windows.windows) - seen_window_ids:
888
+ # vehicle.windows.windows[window_to_remove].enabled = False
889
+ # vehicle.windows.windows.pop(window_to_remove)
890
+ # if all_windows_closed:
891
+ # vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
892
+ # else:
893
+ # vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
894
+ # else:
895
+ # vehicle.windows.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
896
+ # vehicle.windows.windows = {}
897
+ # if 'lights' in vehicle_status_data and vehicle_status_data['lights'] is not None:
898
+ # seen_light_ids: set[str] = set()
899
+ # if 'overallStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['overallStatus'] is not None:
900
+ # if vehicle_status_data['lights']['overallStatus'] == 'ON':
901
+ # vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
902
+ # elif vehicle_status_data['lights']['overallStatus'] == 'OFF':
903
+ # vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
904
+ # elif vehicle_status_data['lights']['overallStatus'] == 'INVALID':
905
+ # vehicle.lights.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
906
+ # else:
907
+ # LOG_API.info('Unknown light status %s', vehicle_status_data['lights']['overallStatus'])
908
+ # vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
909
+ # else:
910
+ # vehicle.lights.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
911
+ # if 'lightsStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['lightsStatus'] is not None:
912
+ # for light_status in vehicle_status_data['lights']['lightsStatus']:
913
+ # if 'name' in light_status and light_status['name'] is not None:
914
+ # light_id: str = light_status['name']
915
+ # seen_light_ids.add(light_id)
916
+ # if light_id in vehicle.lights.lights:
917
+ # light: Lights.Light = vehicle.lights.lights[light_id]
918
+ # else:
919
+ # light = Lights.Light(light_id=light_id, lights=vehicle.lights)
920
+ # vehicle.lights.lights[light_id] = light
921
+ # if 'status' in light_status and light_status['status'] is not None:
922
+ # if light_status['status'] == 'ON':
923
+ # light.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
924
+ # elif light_status['status'] == 'OFF':
925
+ # light.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
926
+ # elif light_status['status'] == 'INVALID':
927
+ # light.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
928
+ # else:
929
+ # LOG_API.info('Unknown light status %s', light_status['status'])
930
+ # light.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
931
+ # else:
932
+ # light.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
933
+ # else:
934
+ # raise APIError('Could not parse light, name missing')
935
+ # log_extra_keys(LOG_API, 'lights', light_status, {'name', 'status'})
936
+ # for light_to_remove in set(vehicle.lights.lights) - seen_light_ids:
937
+ # vehicle.lights.lights[light_to_remove].enabled = False
938
+ # vehicle.lights.lights.pop(light_to_remove)
939
+ # else:
940
+ # vehicle.lights.lights = {}
941
+ # log_extra_keys(LOG_API, 'lights', vehicle_status_data['lights'], {'overallStatus', 'lightsStatus'})
942
+ # log_extra_keys(LOG_API, 'vehicles', vehicle_status_data, {'capturedAt', 'mileageInKm', 'status', 'doors', 'windows', 'lights'})
943
+ # return vehicle
875
944
 
876
945
  def _record_elapsed(self, elapsed: timedelta) -> None:
877
946
  """
@@ -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
@@ -514,6 +515,14 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
514
515
  self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
515
516
  except CarConnectivityError as e:
516
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)
517
526
  LOG_API.info('Received event name %s service event %s for vehicle %s from user %s: %s', data['name'],
518
527
  service_event, vin, user_id, msg.payload)
519
528
  return
@@ -546,10 +555,6 @@ class SkodaMQTTClient(Client): # pylint: disable=too-many-instance-attributes
546
555
  self._skoda_connector.fetch_air_conditioning(vehicle, no_cache=True)
547
556
  except CarConnectivityError as e:
548
557
  LOG.error('Error while fetching air conditioning: %s', e)
549
- #try:
550
- # self._skoda_connector.fetch_vehicle_status_second_api(vehicle, no_cache=True)
551
- #except CarConnectivityError as e:
552
- # LOG.error('Error while fetching status second API: %s', e)
553
558
 
554
559
  if vin in self.delayed_access_function_timers:
555
560
  self.delayed_access_function_timers[vin].cancel()