carconnectivity-connector-skoda 0.1a22__py3-none-any.whl → 0.2a1__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.1a22
3
+ Version: 0.2a1
4
4
  Summary: CarConnectivity connector for Skoda services
5
5
  Author: Till Steinbach
6
6
  License: MIT License
@@ -37,7 +37,7 @@ Classifier: Topic :: Software Development :: Libraries
37
37
  Requires-Python: >=3.8
38
38
  Description-Content-Type: text/markdown
39
39
  License-File: LICENSE
40
- Requires-Dist: carconnectivity
40
+ Requires-Dist: carconnectivity>=0.2a1
41
41
  Requires-Dist: oauthlib~=3.2.2
42
42
  Requires-Dist: requests~=2.32.3
43
43
  Requires-Dist: jwt~=1.3.1
@@ -1,13 +1,13 @@
1
1
  carconnectivity_connectors/skoda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- carconnectivity_connectors/skoda/_version.py,sha256=HEdZtBITW7HcUEt9NLSPGn_UorBnRBrHZWl8fmngNs8,409
3
- carconnectivity_connectors/skoda/capability.py,sha256=JlNEaisVYF8qWv0wNDHTaas36uIpTIQ3NVR69wesiYQ,4513
2
+ carconnectivity_connectors/skoda/_version.py,sha256=4Y9bnt1x-p71kTX4650igUjzXxyHB_QN6k4UFEycuZQ,408
3
+ carconnectivity_connectors/skoda/capability.py,sha256=SnK9xVsqDA5EcWtBznzfWxe6gIpkYdjgY3UzNIc3OCY,4198
4
4
  carconnectivity_connectors/skoda/charging.py,sha256=rG_GoDPetjyjWCyV6l65hgEDU6ths6MkMQ0KL25rbVU,6663
5
5
  carconnectivity_connectors/skoda/climatization.py,sha256=-Nk4tO5C5_YYNQfUIUWBL7mGgR6-J0_pOZplLK8p_ms,1627
6
- carconnectivity_connectors/skoda/command_impl.py,sha256=dtJsiuhwSuR1PXz7AMrdBowHqPxw6DKSAQKk4Z63GG8,2957
7
- carconnectivity_connectors/skoda/connector.py,sha256=rMHAigH9t1P95vGewKxK54umBuqkI6-zFQYw5iPeols,118916
6
+ carconnectivity_connectors/skoda/command_impl.py,sha256=WdgxWPgi82-UgmyFpiSZE-KHRtRjqn7CH-YX9N3bAoI,2875
7
+ carconnectivity_connectors/skoda/connector.py,sha256=2S8DVtk9KX-y9UDRtm9wbtqMUe6JNBe9mn46XsoeceY,105145
8
8
  carconnectivity_connectors/skoda/error.py,sha256=EnzzDxxJ1fswYT5QnMOVSebfoAcqoPmHKcG5i0Tqk3E,2405
9
9
  carconnectivity_connectors/skoda/mqtt_client.py,sha256=lfHJfKOl-FBVd5hV6cS6ZMpZ53ktXyVc4lafvQls-Tk,37748
10
- carconnectivity_connectors/skoda/vehicle.py,sha256=JKLqb6F4RyJ4C3D_sc6kcsdlqxZSlmdJNQfW04m7u78,3204
10
+ carconnectivity_connectors/skoda/vehicle.py,sha256=_ALtlBy7sKVHmqpqAhWNbMd9dto915_SdNWcRi_AqYU,3088
11
11
  carconnectivity_connectors/skoda/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  carconnectivity_connectors/skoda/auth/auth_util.py,sha256=dGLUbUre0HBsTg_Ii5vW34f8DLrCykYJYCyzEvUBBEE,4434
13
13
  carconnectivity_connectors/skoda/auth/my_skoda_session.py,sha256=lSh23SFJs8opjmPwHTv-KNIKDep_WY4aItSP4Zq7bT8,10396
@@ -15,8 +15,8 @@ carconnectivity_connectors/skoda/auth/openid_session.py,sha256=LusWi2FZZIL3buodG
15
15
  carconnectivity_connectors/skoda/auth/session_manager.py,sha256=Uf1vujuDBYUCAXhYToOsZkgbTtfmY3Qe0ICTfwomBpI,2899
16
16
  carconnectivity_connectors/skoda/auth/skoda_web_session.py,sha256=cjzMkzx473Sh-4RgZAQULeRRcxB1MboddldCVM_y5LE,10640
17
17
  carconnectivity_connectors/skoda/auth/helpers/blacklist_retry.py,sha256=f3wsiY5bpHDBxp7Va1Mv9nKJ4u3qnCHZZmDu78_AhMk,1251
18
- carconnectivity_connector_skoda-0.1a22.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
19
- carconnectivity_connector_skoda-0.1a22.dist-info/METADATA,sha256=d5o6lGEA7DgbRIAn0be_LDLiLLXOIOmkGRcAdwodadw,5327
20
- carconnectivity_connector_skoda-0.1a22.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
21
- carconnectivity_connector_skoda-0.1a22.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
22
- carconnectivity_connector_skoda-0.1a22.dist-info/RECORD,,
18
+ carconnectivity_connector_skoda-0.2a1.dist-info/LICENSE,sha256=PIwI1alwDyOfvEQHdGCm2u9uf_mGE8030xZDfun0xTo,1071
19
+ carconnectivity_connector_skoda-0.2a1.dist-info/METADATA,sha256=gd-yKmVlkqZxS3VPnPOVx_ixUTdNWMJw0XpTiqRVtu4,5333
20
+ carconnectivity_connector_skoda-0.2a1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
21
+ carconnectivity_connector_skoda-0.2a1.dist-info/top_level.txt,sha256=KqA8GviZsDH4PtmnwSQsz0HB_w-TWkeEHLIRNo5dTaI,27
22
+ carconnectivity_connector_skoda-0.2a1.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.1a22'
16
- __version_tuple__ = version_tuple = (0, 1)
15
+ __version__ = version = '0.2a1'
16
+ __version_tuple__ = version_tuple = (0, 2)
@@ -89,12 +89,6 @@ class Capabilities(GenericObject):
89
89
  """
90
90
  return capability_id in self.__capabilities
91
91
 
92
- def __str__(self) -> str:
93
- return_string = 'Capabilities:\n'
94
- for capability in self.__capabilities.values():
95
- return_string += f'\t{capability}\n'
96
- return return_string
97
-
98
92
 
99
93
  class Capability(GenericObject):
100
94
  """
@@ -113,10 +107,6 @@ class Capability(GenericObject):
113
107
  self.enabled = True
114
108
  self.delay_notifications = False
115
109
 
116
- def __str__(self) -> str:
117
- return_string = f'{self.capability_id}'
118
- return return_string
119
-
120
110
  class Status(IntEnum):
121
111
  """
122
112
  Enum for capability status.
@@ -14,14 +14,12 @@ from carconnectivity.util import ThrowingArgumentParser
14
14
  if TYPE_CHECKING:
15
15
  from carconnectivity.objects import Optional
16
16
 
17
- LOG: logging.Logger = logging.getLogger("carconnectivity")
17
+ LOG: logging.Logger = logging.getLogger("carconnectivity.connectors.skoda")
18
18
 
19
19
 
20
20
  class SpinCommand(GenericCommand):
21
21
  """
22
- LockUnlockCommand is a command class for locking and unlocking the vehicle.
23
-
24
- Command (Enum): Enum class representing different commands for locking.
22
+ SpinCommand is a command class for verifying the spin
25
23
 
26
24
  """
27
25
  def __init__(self, name: str = 'spin', parent: Optional[GenericObject] = None) -> None:
@@ -15,7 +15,7 @@ import requests
15
15
  from carconnectivity.garage import Garage
16
16
  from carconnectivity.vehicle import GenericVehicle
17
17
  from carconnectivity.errors import AuthenticationError, TooManyRequestsError, RetrievalError, APIError, APICompatibilityError, \
18
- TemporaryAuthenticationError, ConfigurationError, SetterError
18
+ TemporaryAuthenticationError, ConfigurationError, SetterError, CommandError
19
19
  from carconnectivity.util import robust_time_parse, log_extra_keys, config_remove_credentials
20
20
  from carconnectivity.units import Length, Speed, Power, Temperature
21
21
  from carconnectivity.doors import Doors
@@ -28,7 +28,7 @@ from carconnectivity.position import Position
28
28
  from carconnectivity.climatization import Climatization
29
29
  from carconnectivity.charging_connector import ChargingConnector
30
30
  from carconnectivity.commands import Commands
31
- from carconnectivity.command_impl import ClimatizationStartStopCommand, ChargingStartStopCommand, HonkAndFlashCommand, LockUnlockCommand
31
+ from carconnectivity.command_impl import ClimatizationStartStopCommand, ChargingStartStopCommand, HonkAndFlashCommand, LockUnlockCommand, WakeSleepCommand
32
32
 
33
33
  from carconnectivity_connectors.base.connector import BaseConnector
34
34
  from carconnectivity_connectors.skoda.auth.session_manager import SessionManager, SessionUser, Service
@@ -255,6 +255,12 @@ class Connector(BaseConnector):
255
255
 
256
256
  This method calls the `fetch_vehicles` method to retrieve vehicle data.
257
257
  """
258
+ # Add spin command
259
+ if self.commands is not None and not self.commands.contains_command('spin'):
260
+ spin_command = SpinCommand(parent=self.commands)
261
+ spin_command._add_on_set_hook(self.__on_spin) # pylint: disable=protected-access
262
+ spin_command.enabled = True
263
+ self.commands.add_command(spin_command)
258
264
  self.fetch_vehicles()
259
265
  self.car_connectivity.transaction_end()
260
266
 
@@ -887,6 +893,14 @@ class Connector(BaseConnector):
887
893
  else:
888
894
  vehicle.capabilities.clear_capabilities()
889
895
 
896
+ if vehicle.capabilities.has_capability('VEHICLE_WAKE_UP_TRIGGER'):
897
+ if vehicle.commands is not None and vehicle.commands.commands is not None \
898
+ and not vehicle.commands.contains_command('wake-sleep'):
899
+ wake_sleep_command = WakeSleepCommand(parent=vehicle.commands)
900
+ wake_sleep_command._add_on_set_hook(self.__on_wake_sleep) # pylint: disable=protected-access
901
+ wake_sleep_command.enabled = True
902
+ vehicle.commands.add_command(wake_sleep_command)
903
+
890
904
  # Add HONK_AND_FLASH command if necessary capabilities are available
891
905
  if vehicle.capabilities.has_capability('HONK_AND_FLASH') and vehicle.capabilities.has_capability('PARKING_POSITION'):
892
906
  if vehicle.commands is not None and vehicle.commands.commands is not None \
@@ -905,14 +919,6 @@ class Connector(BaseConnector):
905
919
  lock_unlock_command.enabled = True
906
920
  vehicle.doors.commands.add_command(lock_unlock_command)
907
921
 
908
- # Add spin command
909
- if vehicle.commands is not None and vehicle.commands.commands is not None \
910
- and not vehicle.commands.contains_command('spin'):
911
- spin_command = SpinCommand(parent=self.commands)
912
- spin_command._add_on_set_hook(self.__on_spin) # pylint: disable=protected-access
913
- spin_command.enabled = True
914
- vehicle.commands.add_command(spin_command)
915
-
916
922
  if 'specification' in vehicle_data and vehicle_data['specification'] is not None:
917
923
  if 'model' in vehicle_data['specification'] and vehicle_data['specification']['model'] is not None:
918
924
  vehicle.model._set_value(vehicle_data['specification']['model']) # pylint: disable=protected-access
@@ -1128,187 +1134,6 @@ class Connector(BaseConnector):
1128
1134
  log_extra_keys(LOG_API, f'/api/v2/vehicle-status/{vin}', vehicle_status_data, {'overall', 'carCapturedTimestamp'})
1129
1135
  return vehicle
1130
1136
 
1131
- # def fetch_vehicle_status_second_api(self, vehicle: SkodaVehicle, no_cache: bool = False) -> SkodaVehicle:
1132
- # """
1133
- # Fetches the status of a vehicle from other Skoda API.
1134
- #
1135
- # Args:
1136
- # vehicle (GenericVehicle): The vehicle object containing the VIN.
1137
- #
1138
- # Returns:
1139
- # None
1140
- # """
1141
- # vin = vehicle.vin.value
1142
- # if vin is None:
1143
- # raise APIError('VIN is missing')
1144
- # url = f'https://api.connect.skoda-auto.cz/api/v2/vehicle-status/{vin}'
1145
- # vehicle_status_data: Dict[str, Any] | None = self._fetch_data(url=url, session=self.session, no_cache=no_cache)
1146
- # if vehicle_status_data:
1147
- # if 'remote' in vehicle_status_data and vehicle_status_data['remote'] is not None:
1148
- # vehicle_status_data = vehicle_status_data['remote']
1149
- # if vehicle_status_data:
1150
- # if 'capturedAt' in vehicle_status_data and vehicle_status_data['capturedAt'] is not None:
1151
- # captured_at: datetime = robust_time_parse(vehicle_status_data['capturedAt'])
1152
- # else:
1153
- # raise APIError('Could not fetch vehicle status, capturedAt missing')
1154
- # if 'mileageInKm' in vehicle_status_data and vehicle_status_data['mileageInKm'] is not None:
1155
- # # pylint: disable-next=protected-access
1156
- # vehicle.odometer._set_value(value=vehicle_status_data['mileageInKm'], measured=captured_at, unit=Length.KM)
1157
- # else:
1158
- # vehicle.odometer._set_value(value=None, measured=captured_at, unit=Length.KM) # pylint: disable=protected-access
1159
- # if 'status' in vehicle_status_data and vehicle_status_data['status'] is not None:
1160
- # if 'open' in vehicle_status_data['status'] and vehicle_status_data['status']['open'] is not None:
1161
- # if vehicle_status_data['status']['open'] == 'YES':
1162
- # vehicle.doors.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1163
- # elif vehicle_status_data['status']['open'] == 'NO':
1164
- # vehicle.doors.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1165
- # else:
1166
- # vehicle.doors.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1167
- # LOG_API.info('Unknown door open state: %s', vehicle_status_data['status']['open'])
1168
- # else:
1169
- # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1170
- # if 'locked' in vehicle_status_data['status'] and vehicle_status_data['status']['locked'] is not None:
1171
- # if vehicle_status_data['status']['locked'] == 'YES':
1172
- # vehicle.doors.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
1173
- # elif vehicle_status_data['status']['locked'] == 'NO':
1174
- # vehicle.doors.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
1175
- # else:
1176
- # vehicle.doors.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1177
- # LOG_API.info('Unknown door lock state: %s', vehicle_status_data['status']['locked'])
1178
- # else:
1179
- # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1180
- # else:
1181
- # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1182
- # vehicle.doors.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1183
- # if 'doors' in vehicle_status_data and vehicle_status_data['doors'] is not None:
1184
- # seen_door_ids: set[str] = set()
1185
- # for door_status in vehicle_status_data['doors']:
1186
- # if 'name' in door_status and door_status['name'] is not None:
1187
- # door_id = door_status['name']
1188
- # seen_door_ids.add(door_id)
1189
- # if door_id in vehicle.doors.doors:
1190
- # door: Doors.Door = vehicle.doors.doors[door_id]
1191
- # else:
1192
- # door = Doors.Door(door_id=door_id, doors=vehicle.doors)
1193
- # vehicle.doors.doors[door_id] = door
1194
- # if 'status' in door_status and door_status['status'] is not None:
1195
- # if door_status['status'] == 'OPEN':
1196
- # door.lock_state._set_value(Doors.LockState.UNLOCKED, measured=captured_at) # pylint: disable=protected-access
1197
- # door.open_state._set_value(Doors.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1198
- # elif door_status['status'] == 'CLOSED':
1199
- # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1200
- # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1201
- # elif door_status['status'] == 'LOCKED':
1202
- # door.lock_state._set_value(Doors.LockState.LOCKED, measured=captured_at) # pylint: disable=protected-access
1203
- # door.open_state._set_value(Doors.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1204
- # elif door_status['status'] == 'UNSUPPORTED':
1205
- # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1206
- # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1207
- # else:
1208
- # LOG_API.info('Unknown door status %s', door_status['status'])
1209
- # door.lock_state._set_value(Doors.LockState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1210
- # door.open_state._set_value(Doors.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1211
- # else:
1212
- # door.lock_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1213
- # door.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1214
- # else:
1215
- # raise APIError('Could not parse door, name missing')
1216
- # log_extra_keys(LOG_API, 'doors', door_status, {'name', 'status'})
1217
- # for door_to_remove in set(vehicle.doors.doors) - seen_door_ids:
1218
- # vehicle.doors.doors[door_to_remove].enabled = False
1219
- # vehicle.doors.doors.pop(door_to_remove)
1220
- # log_extra_keys(LOG_API, 'status', vehicle_status_data['status'], {'open', 'locked'})
1221
- # else:
1222
- # vehicle.doors.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1223
- # vehicle.doors.doors = {}
1224
- # if 'windows' in vehicle_status_data and vehicle_status_data['windows'] is not None:
1225
- # seen_window_ids: set[str] = set()
1226
- # all_windows_closed: bool = True
1227
- # for window_status in vehicle_status_data['windows']:
1228
- # if 'name' in window_status and window_status['name'] is not None:
1229
- # window_id = window_status['name']
1230
- # seen_window_ids.add(window_id)
1231
- # if window_id in vehicle.windows.windows:
1232
- # window: Windows.Window = vehicle.windows.windows[window_id]
1233
- # else:
1234
- # window = Windows.Window(window_id=window_id, windows=vehicle.windows)
1235
- # vehicle.windows.windows[window_id] = window
1236
- # if 'status' in window_status and window_status['status'] is not None:
1237
- # if window_status['status'] == 'OPEN':
1238
- # all_windows_closed = False
1239
- # window.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1240
- # elif window_status['status'] == 'CLOSED':
1241
- # window.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1242
- # elif window_status['status'] == 'UNSUPPORTED':
1243
- # window.open_state._set_value(Windows.OpenState.UNSUPPORTED, measured=captured_at) # pylint: disable=protected-access
1244
- # elif window_status['status'] == 'INVALID':
1245
- # window.open_state._set_value(Windows.OpenState.INVALID, measured=captured_at) # pylint: disable=protected-access
1246
- # else:
1247
- # LOG_API.info('Unknown window status %s', window_status['status'])
1248
- # window.open_state._set_value(Windows.OpenState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1249
- # else:
1250
- # window.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1251
- # else:
1252
- # raise APIError('Could not parse window, name missing')
1253
- # log_extra_keys(LOG_API, 'doors', window_status, {'name', 'status'})
1254
- # for window_to_remove in set(vehicle.windows.windows) - seen_window_ids:
1255
- # vehicle.windows.windows[window_to_remove].enabled = False
1256
- # vehicle.windows.windows.pop(window_to_remove)
1257
- # if all_windows_closed:
1258
- # vehicle.windows.open_state._set_value(Windows.OpenState.CLOSED, measured=captured_at) # pylint: disable=protected-access
1259
- # else:
1260
- # vehicle.windows.open_state._set_value(Windows.OpenState.OPEN, measured=captured_at) # pylint: disable=protected-access
1261
- # else:
1262
- # vehicle.windows.open_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1263
- # vehicle.windows.windows = {}
1264
- # if 'lights' in vehicle_status_data and vehicle_status_data['lights'] is not None:
1265
- # seen_light_ids: set[str] = set()
1266
- # if 'overallStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['overallStatus'] is not None:
1267
- # if vehicle_status_data['lights']['overallStatus'] == 'ON':
1268
- # vehicle.lights.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
1269
- # elif vehicle_status_data['lights']['overallStatus'] == 'OFF':
1270
- # vehicle.lights.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
1271
- # elif vehicle_status_data['lights']['overallStatus'] == 'INVALID':
1272
- # vehicle.lights.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
1273
- # else:
1274
- # LOG_API.info('Unknown light status %s', vehicle_status_data['lights']['overallStatus'])
1275
- # vehicle.lights.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1276
- # else:
1277
- # vehicle.lights.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1278
- # if 'lightsStatus' in vehicle_status_data['lights'] and vehicle_status_data['lights']['lightsStatus'] is not None:
1279
- # for light_status in vehicle_status_data['lights']['lightsStatus']:
1280
- # if 'name' in light_status and light_status['name'] is not None:
1281
- # light_id: str = light_status['name']
1282
- # seen_light_ids.add(light_id)
1283
- # if light_id in vehicle.lights.lights:
1284
- # light: Lights.Light = vehicle.lights.lights[light_id]
1285
- # else:
1286
- # light = Lights.Light(light_id=light_id, lights=vehicle.lights)
1287
- # vehicle.lights.lights[light_id] = light
1288
- # if 'status' in light_status and light_status['status'] is not None:
1289
- # if light_status['status'] == 'ON':
1290
- # light.light_state._set_value(Lights.LightState.ON, measured=captured_at) # pylint: disable=protected-access
1291
- # elif light_status['status'] == 'OFF':
1292
- # light.light_state._set_value(Lights.LightState.OFF, measured=captured_at) # pylint: disable=protected-access
1293
- # elif light_status['status'] == 'INVALID':
1294
- # light.light_state._set_value(Lights.LightState.INVALID, measured=captured_at) # pylint: disable=protected-access
1295
- # else:
1296
- # LOG_API.info('Unknown light status %s', light_status['status'])
1297
- # light.light_state._set_value(Lights.LightState.UNKNOWN, measured=captured_at) # pylint: disable=protected-access
1298
- # else:
1299
- # light.light_state._set_value(None, measured=captured_at) # pylint: disable=protected-access
1300
- # else:
1301
- # raise APIError('Could not parse light, name missing')
1302
- # log_extra_keys(LOG_API, 'lights', light_status, {'name', 'status'})
1303
- # for light_to_remove in set(vehicle.lights.lights) - seen_light_ids:
1304
- # vehicle.lights.lights[light_to_remove].enabled = False
1305
- # vehicle.lights.lights.pop(light_to_remove)
1306
- # else:
1307
- # vehicle.lights.lights = {}
1308
- # log_extra_keys(LOG_API, 'lights', vehicle_status_data['lights'], {'overallStatus', 'lightsStatus'})
1309
- # log_extra_keys(LOG_API, 'vehicles', vehicle_status_data, {'capturedAt', 'mileageInKm', 'status', 'doors', 'windows', 'lights'})
1310
- # return vehicle
1311
-
1312
1137
  def _record_elapsed(self, elapsed: timedelta) -> None:
1313
1138
  """
1314
1139
  Records the elapsed time.
@@ -1445,15 +1270,15 @@ class Connector(BaseConnector):
1445
1270
  -> Union[str, Dict[str, Any]]:
1446
1271
  if start_stop_command.parent is None or start_stop_command.parent.parent is None \
1447
1272
  or start_stop_command.parent.parent.parent is None or not isinstance(start_stop_command.parent.parent.parent, SkodaVehicle):
1448
- raise SetterError('Object hierarchy is not as expected')
1273
+ raise CommandError('Object hierarchy is not as expected')
1449
1274
  if not isinstance(command_arguments, dict):
1450
- raise SetterError('Command arguments are not a dictionary')
1275
+ raise CommandError('Command arguments are not a dictionary')
1451
1276
  vehicle: SkodaVehicle = start_stop_command.parent.parent.parent
1452
1277
  vin: Optional[str] = vehicle.vin.value
1453
1278
  if vin is None:
1454
- raise SetterError('VIN in object hierarchy missing')
1279
+ raise CommandError('VIN in object hierarchy missing')
1455
1280
  if 'command' not in command_arguments:
1456
- raise SetterError('Command argument missing')
1281
+ raise CommandError('Command argument missing')
1457
1282
  command_dict = {}
1458
1283
  if command_arguments['command'] == ClimatizationStartStopCommand.Command.START:
1459
1284
  command_dict['heaterSource'] = 'ELECTRIC'
@@ -1463,7 +1288,7 @@ class Connector(BaseConnector):
1463
1288
  command_dict['targetTemperature']['temperatureValue'] = round(command_arguments['target_temperature'] * 2) / 2
1464
1289
  if 'target_temperature_unit' in command_arguments:
1465
1290
  if not isinstance(command_arguments['target_temperature_unit'], Temperature):
1466
- raise SetterError('Temperature unit is not of type Temperature')
1291
+ raise CommandError('Temperature unit is not of type Temperature')
1467
1292
  if command_arguments['target_temperature_unit'] == Temperature.C:
1468
1293
  command_dict['targetTemperature']['unitInCar'] = 'CELSIUS'
1469
1294
  elif command_arguments['target_temperature_unit'] == Temperature.F:
@@ -1471,7 +1296,7 @@ class Connector(BaseConnector):
1471
1296
  elif command_arguments['target_temperature_unit'] == Temperature.K:
1472
1297
  command_dict['targetTemperature']['unitInCar'] = 'KELVIN'
1473
1298
  else:
1474
- raise SetterError(f'Unknown temperature unit {command_arguments['target_temperature_unit']}')
1299
+ raise CommandError(f'Unknown temperature unit {command_arguments['target_temperature_unit']}')
1475
1300
  else:
1476
1301
  command_dict['targetTemperature']['unitInCar'] = 'CELSIUS'
1477
1302
  elif start_stop_command.parent is not None and (climatization := start_stop_command.parent.parent) is not None \
@@ -1487,7 +1312,7 @@ class Connector(BaseConnector):
1487
1312
  elif climatization.settings.target_temperature.unit == Temperature.K:
1488
1313
  command_dict['targetTemperature']['unitInCar'] = 'KELVIN'
1489
1314
  else:
1490
- raise SetterError(f'Unknown temperature unit {climatization.settings.target_temperature.unit}')
1315
+ raise CommandError(f'Unknown temperature unit {climatization.settings.target_temperature.unit}')
1491
1316
  else:
1492
1317
  command_dict['targetTemperature']['temperatureValue'] = 25.0
1493
1318
  command_dict['targetTemperature']['unitInCar'] = 'CELSIUS'
@@ -1497,26 +1322,26 @@ class Connector(BaseConnector):
1497
1322
  url = f'https://mysmob.api.connect.skoda-auto.cz/api/v2/air-conditioning/{vin}/stop'
1498
1323
  command_response: requests.Response = self.session.post(url, allow_redirects=True)
1499
1324
  else:
1500
- raise SetterError(f'Unknown command {command_arguments["command"]}')
1325
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1501
1326
 
1502
1327
  if command_response.status_code != requests.codes['accepted']:
1503
1328
  LOG.error('Could not start/stop air conditioning (%s: %s)', command_response.status_code, command_response.text)
1504
- raise SetterError(f'Could not start/stop air conditioning ({command_response.status_code}: {command_response.text})')
1329
+ raise CommandError(f'Could not start/stop air conditioning ({command_response.status_code}: {command_response.text})')
1505
1330
  return command_arguments
1506
1331
 
1507
1332
  def __on_charging_start_stop(self, start_stop_command: ChargingStartStopCommand, command_arguments: Union[str, Dict[str, Any]]) \
1508
1333
  -> Union[str, Dict[str, Any]]:
1509
1334
  if start_stop_command.parent is None or start_stop_command.parent.parent is None \
1510
1335
  or start_stop_command.parent.parent.parent is None or not isinstance(start_stop_command.parent.parent.parent, SkodaVehicle):
1511
- raise SetterError('Object hierarchy is not as expected')
1336
+ raise CommandError('Object hierarchy is not as expected')
1512
1337
  if not isinstance(command_arguments, dict):
1513
- raise SetterError('Command arguments are not a dictionary')
1338
+ raise CommandError('Command arguments are not a dictionary')
1514
1339
  vehicle: SkodaVehicle = start_stop_command.parent.parent.parent
1515
1340
  vin: Optional[str] = vehicle.vin.value
1516
1341
  if vin is None:
1517
- raise SetterError('VIN in object hierarchy missing')
1342
+ raise CommandError('VIN in object hierarchy missing')
1518
1343
  if 'command' not in command_arguments:
1519
- raise SetterError('Command argument missing')
1344
+ raise CommandError('Command argument missing')
1520
1345
  if command_arguments['command'] == ChargingStartStopCommand.Command.START:
1521
1346
  url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}/start'
1522
1347
  command_response: requests.Response = self.session.post(url, allow_redirects=True)
@@ -1524,26 +1349,28 @@ class Connector(BaseConnector):
1524
1349
  url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/charging/{vin}/stop'
1525
1350
  command_response: requests.Response = self.session.post(url, allow_redirects=True)
1526
1351
  else:
1527
- raise SetterError(f'Unknown command {command_arguments["command"]}')
1352
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1528
1353
 
1529
1354
  if command_response.status_code != requests.codes['accepted']:
1530
1355
  LOG.error('Could not start/stop charging (%s: %s)', command_response.status_code, command_response.text)
1531
- raise SetterError(f'Could not start/stop charging ({command_response.status_code}: {command_response.text})')
1356
+ raise CommandError(f'Could not start/stop charging ({command_response.status_code}: {command_response.text})')
1532
1357
  return command_arguments
1533
1358
 
1534
1359
  def __on_honk_flash(self, honk_flash_command: HonkAndFlashCommand, command_arguments: Union[str, Dict[str, Any]]) \
1535
1360
  -> Union[str, Dict[str, Any]]:
1536
1361
  if honk_flash_command.parent is None or honk_flash_command.parent.parent is None \
1537
1362
  or not isinstance(honk_flash_command.parent.parent, SkodaVehicle):
1538
- raise SetterError('Object hierarchy is not as expected')
1363
+ raise CommandError('Object hierarchy is not as expected')
1539
1364
  if not isinstance(command_arguments, dict):
1540
- raise SetterError('Command arguments are not a dictionary')
1365
+ raise CommandError('Command arguments are not a dictionary')
1541
1366
  vehicle: SkodaVehicle = honk_flash_command.parent.parent
1542
1367
  vin: Optional[str] = vehicle.vin.value
1543
1368
  if vin is None:
1544
- raise SetterError('VIN in object hierarchy missing')
1369
+ raise CommandError('VIN in object hierarchy missing')
1545
1370
  if 'command' not in command_arguments:
1546
- raise SetterError('Command argument missing')
1371
+ raise CommandError('Command argument missing')
1372
+ if 'duration' in command_arguments:
1373
+ LOG.warning('Duration argument is not supported by the Skoda API')
1547
1374
  command_dict = {}
1548
1375
  if command_arguments['command'] in [HonkAndFlashCommand.Command.FLASH, HonkAndFlashCommand.Command.HONK_AND_FLASH]:
1549
1376
  command_dict['mode'] = command_arguments['command'].name
@@ -1551,7 +1378,7 @@ class Connector(BaseConnector):
1551
1378
  if vehicle.position is None or vehicle.position.latitude is None or vehicle.position.longitude is None \
1552
1379
  or vehicle.position.latitude.value is None or vehicle.position.longitude.value is None \
1553
1380
  or not vehicle.position.latitude.enabled or not vehicle.position.longitude.enabled:
1554
- raise SetterError('Can only execute honk and flash commands if vehicle position is known')
1381
+ raise CommandError('Can only execute honk and flash commands if vehicle position is known')
1555
1382
  command_dict['vehiclePosition']['latitude'] = vehicle.position.latitude.value
1556
1383
  command_dict['vehiclePosition']['longitude'] = vehicle.position.longitude.value
1557
1384
 
@@ -1559,72 +1386,93 @@ class Connector(BaseConnector):
1559
1386
  command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1560
1387
  if command_response.status_code != requests.codes['accepted']:
1561
1388
  LOG.error('Could not execute honk or flash command (%s: %s)', command_response.status_code, command_response.text)
1562
- raise SetterError(f'Could not execute honk or flash command ({command_response.status_code}: {command_response.text})')
1389
+ raise CommandError(f'Could not execute honk or flash command ({command_response.status_code}: {command_response.text})')
1563
1390
  else:
1564
- raise SetterError(f'Unknown command {command_arguments["command"]}')
1391
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1565
1392
  return command_arguments
1566
1393
 
1567
1394
  def __on_lock_unlock(self, lock_unlock_command: LockUnlockCommand, command_arguments: Union[str, Dict[str, Any]]) \
1568
1395
  -> Union[str, Dict[str, Any]]:
1569
1396
  if lock_unlock_command.parent is None or lock_unlock_command.parent.parent is None \
1570
1397
  or lock_unlock_command.parent.parent.parent is None or not isinstance(lock_unlock_command.parent.parent.parent, SkodaVehicle):
1571
- raise SetterError('Object hierarchy is not as expected')
1398
+ raise CommandError('Object hierarchy is not as expected')
1572
1399
  if not isinstance(command_arguments, dict):
1573
1400
  raise SetterError('Command arguments are not a dictionary')
1574
1401
  vehicle: SkodaVehicle = lock_unlock_command.parent.parent.parent
1575
1402
  vin: Optional[str] = vehicle.vin.value
1576
1403
  if vin is None:
1577
- raise SetterError('VIN in object hierarchy missing')
1404
+ raise CommandError('VIN in object hierarchy missing')
1578
1405
  if 'command' not in command_arguments:
1579
- raise SetterError('Command argument missing')
1406
+ raise CommandError('Command argument missing')
1580
1407
  command_dict = {}
1581
1408
  if 'spin' in command_arguments:
1582
1409
  command_dict['currentSpin'] = command_arguments['spin']
1583
1410
  else:
1584
1411
  if self._spin is None:
1585
- raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1412
+ raise CommandError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1586
1413
  command_dict['currentSpin'] = self._spin
1587
1414
  if command_arguments['command'] == LockUnlockCommand.Command.LOCK:
1588
1415
  url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-access/{vin}/lock'
1589
1416
  elif command_arguments['command'] == LockUnlockCommand.Command.UNLOCK:
1590
1417
  url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-access/{vin}/unlock'
1591
1418
  else:
1592
- raise SetterError(f'Unknown command {command_arguments["command"]}')
1419
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1593
1420
  command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1594
1421
  if command_response.status_code != requests.codes['accepted']:
1595
1422
  LOG.error('Could not execute locking command (%s: %s)', command_response.status_code, command_response.text)
1596
- raise SetterError(f'Could not execute locking command ({command_response.status_code}: {command_response.text})')
1423
+ raise CommandError(f'Could not execute locking command ({command_response.status_code}: {command_response.text})')
1597
1424
  return command_arguments
1598
1425
 
1599
- def __on_spin(self, spin_command: SpinCommand, command_arguments: Union[str, Dict[str, Any]]) \
1426
+ def __on_wake_sleep(self, wake_sleep_command: WakeSleepCommand, command_arguments: Union[str, Dict[str, Any]]) \
1600
1427
  -> Union[str, Dict[str, Any]]:
1601
- if spin_command.parent is None or spin_command.parent.parent is None or not isinstance(spin_command.parent.parent, SkodaVehicle):
1602
- raise SetterError('Object hierarchy is not as expected')
1428
+ if wake_sleep_command.parent is None or wake_sleep_command.parent.parent is None \
1429
+ or not isinstance(wake_sleep_command.parent.parent, GenericVehicle):
1430
+ raise CommandError('Object hierarchy is not as expected')
1603
1431
  if not isinstance(command_arguments, dict):
1604
- raise SetterError('Command arguments are not a dictionary')
1605
- vehicle: SkodaVehicle = spin_command.parent.parent
1432
+ raise CommandError('Command arguments are not a dictionary')
1433
+ vehicle: GenericVehicle = wake_sleep_command.parent.parent
1606
1434
  vin: Optional[str] = vehicle.vin.value
1607
1435
  if vin is None:
1608
- raise SetterError('VIN in object hierarchy missing')
1436
+ raise CommandError('VIN in object hierarchy missing')
1609
1437
  if 'command' not in command_arguments:
1610
- raise SetterError('Command argument missing')
1438
+ raise CommandError('Command argument missing')
1439
+ if command_arguments['command'] == WakeSleepCommand.Command.WAKE:
1440
+ url = f'https://mysmob.api.connect.skoda-auto.cz/api/v1/vehicle-wakeup/{vin}?applyRequestLimiter=true'
1441
+
1442
+ command_response: requests.Response = self.session.post(url, data='{}', allow_redirects=True)
1443
+ if command_response.status_code != requests.codes['accepted']:
1444
+ LOG.error('Could not execute wake command (%s: %s)', command_response.status_code, command_response.text)
1445
+ raise CommandError(f'Could not execute wake command ({command_response.status_code}: {command_response.text})')
1446
+ elif command_arguments['command'] == WakeSleepCommand.Command.SLEEP:
1447
+ raise CommandError('Sleep command not supported by vehicle. Vehicle will put itself to sleep')
1448
+ else:
1449
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1450
+ return command_arguments
1451
+
1452
+ def __on_spin(self, spin_command: SpinCommand, command_arguments: Union[str, Dict[str, Any]]) \
1453
+ -> Union[str, Dict[str, Any]]:
1454
+ del spin_command
1455
+ if not isinstance(command_arguments, dict):
1456
+ raise CommandError('Command arguments are not a dictionary')
1457
+ if 'command' not in command_arguments:
1458
+ raise CommandError('Command argument missing')
1611
1459
  command_dict = {}
1612
1460
  if self._spin is None:
1613
- raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1461
+ raise CommandError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1614
1462
  if 'spin' in command_arguments:
1615
1463
  command_dict['currentSpin'] = command_arguments['spin']
1616
1464
  else:
1617
- if self._spin is None:
1618
- raise SetterError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1465
+ if self._spin is None or self._spin == '':
1466
+ raise CommandError('S-PIN is missing, please add S-PIN to your configuration or .netrc file')
1619
1467
  command_dict['currentSpin'] = self._spin
1620
1468
  if command_arguments['command'] == SpinCommand.Command.VERIFY:
1621
- url = 'https://mysmob.api.connect.skoda-auto.cz/v1/spin/verify'
1469
+ url = 'https://mysmob.api.connect.skoda-auto.cz/api/v1/spin/verify'
1622
1470
  else:
1623
- raise SetterError(f'Unknown command {command_arguments["command"]}')
1471
+ raise CommandError(f'Unknown command {command_arguments["command"]}')
1624
1472
  command_response: requests.Response = self.session.post(url, data=json.dumps(command_dict), allow_redirects=True)
1625
- if command_response.status_code != requests.codes['accepted']:
1473
+ if command_response.status_code != requests.codes['ok']:
1626
1474
  LOG.error('Could not execute spin command (%s: %s)', command_response.status_code, command_response.text)
1627
- raise SetterError(f'Could not execute spin command ({command_response.status_code}: {command_response.text})')
1475
+ raise CommandError(f'Could not execute spin command ({command_response.status_code}: {command_response.text})')
1628
1476
  else:
1629
1477
  LOG.info('Spin verify command executed successfully')
1630
1478
  return command_arguments
@@ -29,10 +29,6 @@ class SkodaVehicle(GenericVehicle): # pylint: disable=too-many-instance-attribu
29
29
  self.capabilities = Capabilities(vehicle=self)
30
30
  self.manufacturer._set_value(value='Škoda') # pylint: disable=protected-access
31
31
 
32
- def __str__(self) -> str:
33
- return_string: str = f'\t{self.capabilities}\n'
34
- return return_string
35
-
36
32
 
37
33
  class SkodaElectricVehicle(ElectricVehicle, SkodaVehicle):
38
34
  """