myvsb-developer-api 1.0.0__tar.gz → 1.0.2__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.
Files changed (28) hide show
  1. {myvsb_developer_api-1.0.0/src/myvsb_developer_api.egg-info → myvsb_developer_api-1.0.2}/PKG-INFO +1 -1
  2. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/pyproject.toml +1 -1
  3. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/api_layer/exceptions.py +6 -2
  4. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/api_layer/open_api_client.py +23 -15
  5. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/api_layer/rest_api.py +20 -6
  6. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/air_conditioning.py +0 -1
  7. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/auxiliary_heating.py +1 -0
  8. myvsb_developer_api-1.0.2/src/myskoda_openapi/models/configurations.py +34 -0
  9. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2/src/myvsb_developer_api.egg-info}/PKG-INFO +1 -1
  10. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myvsb_developer_api.egg-info/SOURCES.txt +1 -0
  11. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/LICENSE +0 -0
  12. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/README.md +0 -0
  13. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/setup.cfg +0 -0
  14. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/api_layer/const.py +0 -0
  15. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/api_layer/utils.py +0 -0
  16. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/active_ventilation.py +0 -0
  17. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/base_model.py +0 -0
  18. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/charging.py +0 -0
  19. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/charging_profiles.py +0 -0
  20. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/common.py +0 -0
  21. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/driving_range.py +0 -0
  22. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/enums.py +0 -0
  23. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/parking_position.py +0 -0
  24. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/vehicle.py +0 -0
  25. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myskoda_openapi/models/vehicle_status.py +0 -0
  26. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myvsb_developer_api.egg-info/dependency_links.txt +0 -0
  27. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myvsb_developer_api.egg-info/requires.txt +0 -0
  28. {myvsb_developer_api-1.0.0 → myvsb_developer_api-1.0.2}/src/myvsb_developer_api.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: myvsb-developer-api
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Asynchronous Python library for the MyVSB Developer API
5
5
  Author-email: net0045 <stepan.netolicky@vsb.cz>
6
6
  Project-URL: Homepage, https://github.com/mobility-lab-vsb/myvsb-developer-api
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "myvsb-developer-api"
7
- version = "1.0.0"
7
+ version = "1.0.2"
8
8
  authors = [
9
9
  { name="net0045", email="stepan.netolicky@vsb.cz" },
10
10
  ]
@@ -25,6 +25,10 @@ class OpenApiVehicleNotFoundError(OpenApiError):
25
25
  def __init__(self, message: str = "Vehicle with this VIN does not exist.") -> None:
26
26
  super().__init__(message, status_code=404)
27
27
 
28
+ class OpenApiUnsupportedError(OpenApiError):
29
+ """Error 422 - Unsupported operation."""
30
+ def __init__(self, message: str = "Vehicle does not support this operation") -> None:
31
+ super().__init__(message, status_code=422)
28
32
 
29
33
  class OpenApiRateLimitError(OpenApiError):
30
34
  """Error 429 - Rate limit exceeded or weak 12V battery."""
@@ -32,6 +36,6 @@ class OpenApiRateLimitError(OpenApiError):
32
36
  super().__init__(message, status_code=429)
33
37
 
34
38
  class OpenApiServerError(OpenApiError):
35
- """Error 500 / 504 - Server error or timeout."""
39
+ """Error 500 - Server error or timeout."""
36
40
  def __init__(self, message: str, status_code: int = 500) -> None:
37
- super().__init__(message, status_code=status_code)
41
+ super().__init__(message, status_code=status_code)
@@ -11,6 +11,7 @@ from ..models.auxiliary_heating import AuxiliaryHeating
11
11
  from ..models.charging import Charging
12
12
  from ..models.driving_range import FuelStatus
13
13
  from ..models.charging_profiles import ChargingProfiles
14
+ from ..models.configurations import StartAirConditioningConfiguration, StartAuxiliaryHeatingConfiguration, ConfigurationTargetTemperature
14
15
 
15
16
  class OpenAPIClient:
16
17
  """Client for interacting with rest API and used in HomeAssistant."""
@@ -70,10 +71,16 @@ class OpenAPIClient:
70
71
 
71
72
 
72
73
 
73
- async def start_air_conditioning(self, vin: str, temperature: float) -> None:
74
+ async def start_air_conditioning(self, vin: str, temperature: float, unit: str = "CELSIUS", without_external_power: bool = True) -> None:
74
75
  """Starts the air conditioning for the vehicle with the given VIN."""
75
- payload = {"targetTemperature": temperature}
76
- await self.rest_api.start_air_conditioning(vin, payload=payload)
76
+ config = StartAirConditioningConfiguration(
77
+ target_temperature=ConfigurationTargetTemperature(
78
+ temperature_value=temperature,
79
+ unit_in_car=unit,
80
+ ),
81
+ air_conditioning_without_external_power=without_external_power,
82
+ )
83
+ await self.rest_api.start_air_conditioning(vin, config)
77
84
 
78
85
  async def stop_air_conditioning(self, vin: str) -> None:
79
86
  """Stops the air_conditioning of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant"""
@@ -81,19 +88,20 @@ class OpenAPIClient:
81
88
 
82
89
  async def start_auxiliary_heating(self, vin: str, spin: str, duration_in_seconds: int = 120, start_mode: str = "HEATING", target_temperature: Optional[float] = None, unit: str = "CELSIUS") -> None:
83
90
  """Starts the auxiliary heating for the vehicle with the given VIN."""
84
- payload = {
85
- "spin": spin,
86
- "durationInSeconds": duration_in_seconds,
87
- "startMode": start_mode
88
- }
89
- # If there is target temperature, add it into the payload
91
+ temp_obj = None
90
92
  if target_temperature is not None:
91
- payload["targetTemperature"] = {
92
- "value": target_temperature,
93
- "unit": unit
94
- }
95
-
96
- await self.rest_api.start_auxiliary_heating(vin, payload=payload)
93
+ temp_obj = ConfigurationTargetTemperature(
94
+ temperature_value=target_temperature,
95
+ unit_in_car=unit,
96
+ )
97
+
98
+ config = StartAuxiliaryHeatingConfiguration(
99
+ spin=spin,
100
+ duration_in_seconds=duration_in_seconds,
101
+ start_mode=start_mode,
102
+ target_temperature=temp_obj,
103
+ )
104
+ await self.rest_api.start_auxiliary_heating(vin, config)
97
105
 
98
106
  async def stop_auxiliary_heating(self, vin: str) -> None:
99
107
  """Stops the auxiliary_heating of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant"""
@@ -14,12 +14,15 @@ from ..models.charging import Charging
14
14
  from ..models.active_ventilation import ActiveVentilation
15
15
  from ..models.charging_profiles import ChargingProfiles
16
16
  from ..models.driving_range import FuelStatus
17
+ from ..models.configurations import StartAirConditioningConfiguration, StartAuxiliaryHeatingConfiguration
17
18
  from .exceptions import (
18
19
  OpenApiError,
19
20
  OpenApiAuthenticationError,
21
+ OpenApiUnsupportedError,
20
22
  OpenApiForbiddenError,
21
23
  OpenApiVehicleNotFoundError,
22
24
  OpenApiRateLimitError,
25
+ OpenApiServerError
23
26
  )
24
27
 
25
28
  T = TypeVar("T")
@@ -65,8 +68,12 @@ class SkodaRestAPI:
65
68
  case 401: raise OpenApiAuthenticationError("Invalid or expired X-API-Key.")
66
69
  case 403: raise OpenApiForbiddenError("Access forbidden. User not allowed to execute operation.")
67
70
  case 404: raise OpenApiVehicleNotFoundError("Vehicle with this VIN does not exist.")
71
+ case 422: raise OpenApiUnsupportedError("Vehicle does not support this operation")
68
72
  case 429: raise OpenApiRateLimitError("Rate limit exceeded or insufficient battery level.")
69
73
  case 400: raise OpenApiError("Bad request (e.g. validation or VIN issues).")
74
+ case 500: raise OpenApiServerError("An unexpected error occurred while processing the request.", 500)
75
+ case 503: raise OpenApiServerError("API key validation is temporarily unavailable. Retry after 10 seconds.", 503)
76
+ case 504: raise OpenApiServerError("The vehicle did not respond in time.", 504)
70
77
 
71
78
  return response.status
72
79
  except Exception as err:
@@ -86,10 +93,15 @@ class SkodaRestAPI:
86
93
  async with self._session.get(full_url, headers=headers, params=params) as response:
87
94
  if response.status not in (200, 202):
88
95
  match response.status:
89
- case 401: raise OpenApiAuthenticationError("Invalid or expired X-API-Key.")
90
- case 403: raise OpenApiForbiddenError("Access to the requested resource is forbidden.")
91
- case 404: raise OpenApiVehicleNotFoundError("Vehicle with this VIN does not exist.")
92
- case 429: raise OpenApiRateLimitError("Rate limit exceeded or weak 12V battery.")
96
+ case 401: raise OpenApiAuthenticationError("Invalid or expired X-API-Key.")
97
+ case 403: raise OpenApiForbiddenError("Access forbidden. User not allowed to execute operation.")
98
+ case 404: raise OpenApiVehicleNotFoundError("Vehicle with this VIN does not exist.")
99
+ case 422: raise OpenApiUnsupportedError("Vehicle does not support this operation")
100
+ case 429: raise OpenApiRateLimitError("Rate limit exceeded or insufficient battery level.")
101
+ case 400: raise OpenApiError("Bad request (e.g. validation or VIN issues).")
102
+ case 500: raise OpenApiServerError("An unexpected error occurred while processing the request.", 500)
103
+ case 503: raise OpenApiServerError("API key validation is temporarily unavailable. Retry after 10 seconds.", 503)
104
+ case 504: raise OpenApiServerError("The vehicle did not respond in time.", 504)
93
105
  return await response.json()
94
106
  except Exception as err:
95
107
  raise OpenApiError(f"There has been an error when trying to make the request: {err}") from err
@@ -224,10 +236,11 @@ class SkodaRestAPI:
224
236
  # =========================================================================
225
237
  # ENDPOINT METHODS - POST
226
238
  # =========================================================================
227
- async def start_air_conditioning(self, vin: str, payload: dict) -> PostEndpointResult:
239
+ async def start_air_conditioning(self, vin: str, config: StartAirConditioningConfiguration) -> PostEndpointResult:
228
240
  """Starts the air conditioning for the vehicle with the given VIN. The payload should contain any necessary parameters for starting the air conditioning."""
229
241
  url = f"/api/v1/vehicles/{vin}/air-conditioning/start"
230
242
 
243
+ payload = config.model_dump(by_alias=True, exclude_none=True)
231
244
  status = await self._make_post_request(url, json_data=payload)
232
245
  return PostEndpointResult(url=url, status=status, headers={})
233
246
 
@@ -238,10 +251,11 @@ class SkodaRestAPI:
238
251
  status = await self._make_post_request(url)
239
252
  return PostEndpointResult(url=url, status=status, headers={})
240
253
 
241
- async def start_auxiliary_heating(self, vin: str, payload: dict) -> PostEndpointResult:
254
+ async def start_auxiliary_heating(self, vin: str, config: StartAuxiliaryHeatingConfiguration) -> PostEndpointResult:
242
255
  """Starts the auxiliary heating for the vehicle with the given VIN. The payload should contain any necessary parameters for starting the auxiliary heating."""
243
256
  url = f"/api/v1/vehicles/{vin}/auxiliary-heating/start"
244
257
 
258
+ payload = config.model_dump(by_alias=True, exclude_none=True)
245
259
  status = await self._make_post_request(url, json_data=payload)
246
260
  return PostEndpointResult(url=url, status=status, headers={})
247
261
 
@@ -11,7 +11,6 @@ class WindowHeating(BaseModel):
11
11
  front: Optional[OnOffState] = None
12
12
  rear: Optional[OnOffState] = None
13
13
 
14
-
15
14
  class AirConditioning(BaseModel):
16
15
  """Information about the vehicle's air conditioning."""
17
16
  state: AirConditioningState
@@ -6,6 +6,7 @@ from .enums import (
6
6
  AuxiliaryHeatingStartMode,
7
7
  )
8
8
 
9
+
9
10
  class AuxiliaryHeating(BaseModel):
10
11
  """Auxiliary heating status."""
11
12
  state: AuxiliaryHeatingState
@@ -0,0 +1,34 @@
1
+ from typing import Optional
2
+ from pydantic import Field
3
+ from .base_model import BaseModel
4
+
5
+ class ConfigurationTargetTemperature(BaseModel):
6
+ temperature_value: float = Field(..., alias="temperatureValue")
7
+ unit_in_car: str = Field("CELSIUS", alias="unitInCar")
8
+
9
+ class Config:
10
+ populate_by_name = True
11
+
12
+
13
+ class StartAirConditioningConfiguration(BaseModel):
14
+ """Configuration for starting air conditioning."""
15
+ target_temperature: Optional[ConfigurationTargetTemperature] = Field(None, alias="targetTemperature")
16
+ spin: Optional[str] = Field(None, alias="spin")
17
+ heater_source: Optional[str] = Field(None, alias="heaterSource")
18
+ air_conditioning_without_external_power: Optional[bool] = Field(
19
+ True, alias="airConditioningWithoutExternalPower"
20
+ )
21
+
22
+ class Config:
23
+ populate_by_name = True
24
+
25
+
26
+ class StartAuxiliaryHeatingConfiguration(BaseModel):
27
+ """Configuration for starting auxiliary heating."""
28
+ spin: str = Field(..., alias="spin")
29
+ duration_in_seconds: Optional[int] = Field(120, alias="durationInSeconds")
30
+ start_mode: Optional[str] = Field("HEATING", alias="startMode")
31
+ target_temperature: Optional[ConfigurationTargetTemperature] = Field(None, alias="targetTemperature")
32
+
33
+ class Config:
34
+ populate_by_name = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: myvsb-developer-api
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Asynchronous Python library for the MyVSB Developer API
5
5
  Author-email: net0045 <stepan.netolicky@vsb.cz>
6
6
  Project-URL: Homepage, https://github.com/mobility-lab-vsb/myvsb-developer-api
@@ -13,6 +13,7 @@ src/myskoda_openapi/models/base_model.py
13
13
  src/myskoda_openapi/models/charging.py
14
14
  src/myskoda_openapi/models/charging_profiles.py
15
15
  src/myskoda_openapi/models/common.py
16
+ src/myskoda_openapi/models/configurations.py
16
17
  src/myskoda_openapi/models/driving_range.py
17
18
  src/myskoda_openapi/models/enums.py
18
19
  src/myskoda_openapi/models/parking_position.py