skoda-public-api 1.1.1__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.
- skoda_public_api-1.1.1/LICENSE +21 -0
- skoda_public_api-1.1.1/PKG-INFO +117 -0
- skoda_public_api-1.1.1/README.md +88 -0
- skoda_public_api-1.1.1/pyproject.toml +53 -0
- skoda_public_api-1.1.1/setup.cfg +4 -0
- skoda_public_api-1.1.1/src/skoda_public_api/api_layer/const.py +25 -0
- skoda_public_api-1.1.1/src/skoda_public_api/api_layer/exceptions.py +41 -0
- skoda_public_api-1.1.1/src/skoda_public_api/api_layer/open_api_client.py +202 -0
- skoda_public_api-1.1.1/src/skoda_public_api/api_layer/rest_api.py +302 -0
- skoda_public_api-1.1.1/src/skoda_public_api/api_layer/utils.py +0 -0
- skoda_public_api-1.1.1/src/skoda_public_api/cli/__init__.py +125 -0
- skoda_public_api-1.1.1/src/skoda_public_api/cli/__main__.py +6 -0
- skoda_public_api-1.1.1/src/skoda_public_api/cli/operations.py +165 -0
- skoda_public_api-1.1.1/src/skoda_public_api/cli/requests.py +107 -0
- skoda_public_api-1.1.1/src/skoda_public_api/cli/utils.py +110 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/active_ventilation.py +12 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/air_conditioning.py +22 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/auxiliary_heating.py +17 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/base_model.py +13 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/charging.py +44 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/charging_profiles.py +53 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/common.py +20 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/configurations.py +23 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/driving_range.py +21 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/enums.py +135 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/parking_position.py +17 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/vehicle.py +43 -0
- skoda_public_api-1.1.1/src/skoda_public_api/models/vehicle_status.py +33 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/PKG-INFO +117 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/SOURCES.txt +32 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/dependency_links.txt +1 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/entry_points.txt +2 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/requires.txt +13 -0
- skoda_public_api-1.1.1/src/skoda_public_api.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mobility Lab @ VSB - Technical University of Ostrava
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: skoda-public-api
|
|
3
|
+
Version: 1.1.1
|
|
4
|
+
Summary: Asynchronous Python library for the Škoda public API
|
|
5
|
+
Author: Mobility Lab, VŠB-TUO
|
|
6
|
+
Author-email: TomVSB <tomas.mrovec@vsb.cz>, net0045 <stepan.netolicky@vsb.cz>, mag0051 <david.magyarics@vsb.cz>
|
|
7
|
+
Maintainer-email: mag0051 <david.magyarics@vsb.cz>, TomVSB <tomas.mrovec@vsb.cz>
|
|
8
|
+
Project-URL: Homepage, https://github.com/mobility-lab-vsb/skoda-public-api
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/mobility-lab-vsb/skoda-public-api/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: aiohttp>=3.9.0
|
|
18
|
+
Requires-Dist: pydantic>=2.5.0
|
|
19
|
+
Provides-Extra: test
|
|
20
|
+
Requires-Dist: pytest>=9.0.0; extra == "test"
|
|
21
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "test"
|
|
22
|
+
Requires-Dist: aresponses>=3.0.0; extra == "test"
|
|
23
|
+
Provides-Extra: cli
|
|
24
|
+
Requires-Dist: asyncclick~=8.1; extra == "cli"
|
|
25
|
+
Requires-Dist: coloredlogs~=15.0; extra == "cli"
|
|
26
|
+
Requires-Dist: pygments~=2.18; extra == "cli"
|
|
27
|
+
Requires-Dist: pyyaml~=6.0; extra == "cli"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# skoda-public-api
|
|
31
|
+
|
|
32
|
+
[](LICENSE)
|
|
33
|
+
[](pyproject.toml)
|
|
34
|
+
|
|
35
|
+
Asynchronous Python library for the Škoda public API, developed by [Mobility Lab @ VSB](https://github.com/mobility-lab-vsb) — Technical University of Ostrava. It provides typed access to connected-vehicle data (status, odometer, charging, climate, fuel, parking position) and remote vehicle control (climate, charging, ventilation) for Škoda vehicles.
|
|
36
|
+
|
|
37
|
+
It is built on [`aiohttp`](https://docs.aiohttp.org/) and [`pydantic`](https://docs.pydantic.dev/), and ships both as a library and as a standalone CLI (`skodactl`).
|
|
38
|
+
|
|
39
|
+
This version targets **API v1** of the [Škoda public API](https://public.api.connect.skoda-auto.cz/docs).
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
pip install skoda-public-api
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## As a library
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
import asyncio
|
|
51
|
+
|
|
52
|
+
from aiohttp import ClientSession
|
|
53
|
+
|
|
54
|
+
from skoda_public_api.api_layer.open_api_client import OpenAPIClient
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
async def main() -> None:
|
|
58
|
+
async with ClientSession() as session:
|
|
59
|
+
client = OpenAPIClient(api_key="XXX", session=session)
|
|
60
|
+
|
|
61
|
+
vehicle = await client.get_vehicle("TMBJX7NY4PM054321")
|
|
62
|
+
print(vehicle.vehicle.name)
|
|
63
|
+
|
|
64
|
+
charging = await client.get_charging("TMBJX7NY4PM054321")
|
|
65
|
+
print(charging.status.battery.state_of_charge_in_percent)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Every response is a typed `pydantic` model — see [`src/skoda_public_api/models`](src/skoda_public_api/models) for the full data model, and [`src/skoda_public_api/api_layer/open_api_client.py`](src/skoda_public_api/api_layer/open_api_client.py) for the full list of available reads (vehicle status, odometer, charging, air conditioning, auxiliary heating, active ventilation, fuel status, parking position, charging profiles) and remote actions (start/stop charging, climate, auxiliary heating, active ventilation, window heating, charge limit, target temperature).
|
|
72
|
+
|
|
73
|
+
## As CLI
|
|
74
|
+
|
|
75
|
+
The library ships with a command line interface called `skodactl`, which is useful for manually
|
|
76
|
+
testing the API endpoints. Install it together with the CLI dependencies:
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
pip install "skoda-public-api[cli]"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
You authenticate with your API key, either via the `--api-key` option or the `SKODA_API_KEY`
|
|
83
|
+
environment variable, and address a vehicle by its VIN:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
skodactl --api-key XXX get-vehicle TMBJX7NY4PM054321
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
By default, the CLI talks to the production endpoint. Point it at the public test endpoint with
|
|
90
|
+
`--endpoint test`, switch to YAML output with `--format yaml`, or log HTTP requests and responses
|
|
91
|
+
with `--trace`:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
skodactl --api-key XXX --endpoint test get-vehicle-status TMBJX7NY4PM054321
|
|
95
|
+
SKODA_API_KEY=XXX skodactl --format yaml --trace get-charging TMBJX7NY4PM054321
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Remote operations can be started as well:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
skodactl --api-key XXX start-air-conditioning TMBJX7NY4PM054321 --temperature 21
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Run `skodactl --help` for the full list of commands and options.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
Clone the repository and install it in editable mode together with the test dependencies:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
pip install -e ".[test,cli]"
|
|
112
|
+
pytest
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
Distributed under the MIT License. See [`LICENSE`](LICENSE) for details.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# skoda-public-api
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](pyproject.toml)
|
|
5
|
+
|
|
6
|
+
Asynchronous Python library for the Škoda public API, developed by [Mobility Lab @ VSB](https://github.com/mobility-lab-vsb) — Technical University of Ostrava. It provides typed access to connected-vehicle data (status, odometer, charging, climate, fuel, parking position) and remote vehicle control (climate, charging, ventilation) for Škoda vehicles.
|
|
7
|
+
|
|
8
|
+
It is built on [`aiohttp`](https://docs.aiohttp.org/) and [`pydantic`](https://docs.pydantic.dev/), and ships both as a library and as a standalone CLI (`skodactl`).
|
|
9
|
+
|
|
10
|
+
This version targets **API v1** of the [Škoda public API](https://public.api.connect.skoda-auto.cz/docs).
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```sh
|
|
15
|
+
pip install skoda-public-api
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## As a library
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import asyncio
|
|
22
|
+
|
|
23
|
+
from aiohttp import ClientSession
|
|
24
|
+
|
|
25
|
+
from skoda_public_api.api_layer.open_api_client import OpenAPIClient
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
async def main() -> None:
|
|
29
|
+
async with ClientSession() as session:
|
|
30
|
+
client = OpenAPIClient(api_key="XXX", session=session)
|
|
31
|
+
|
|
32
|
+
vehicle = await client.get_vehicle("TMBJX7NY4PM054321")
|
|
33
|
+
print(vehicle.vehicle.name)
|
|
34
|
+
|
|
35
|
+
charging = await client.get_charging("TMBJX7NY4PM054321")
|
|
36
|
+
print(charging.status.battery.state_of_charge_in_percent)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
asyncio.run(main())
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Every response is a typed `pydantic` model — see [`src/skoda_public_api/models`](src/skoda_public_api/models) for the full data model, and [`src/skoda_public_api/api_layer/open_api_client.py`](src/skoda_public_api/api_layer/open_api_client.py) for the full list of available reads (vehicle status, odometer, charging, air conditioning, auxiliary heating, active ventilation, fuel status, parking position, charging profiles) and remote actions (start/stop charging, climate, auxiliary heating, active ventilation, window heating, charge limit, target temperature).
|
|
43
|
+
|
|
44
|
+
## As CLI
|
|
45
|
+
|
|
46
|
+
The library ships with a command line interface called `skodactl`, which is useful for manually
|
|
47
|
+
testing the API endpoints. Install it together with the CLI dependencies:
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
pip install "skoda-public-api[cli]"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
You authenticate with your API key, either via the `--api-key` option or the `SKODA_API_KEY`
|
|
54
|
+
environment variable, and address a vehicle by its VIN:
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
skodactl --api-key XXX get-vehicle TMBJX7NY4PM054321
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
By default, the CLI talks to the production endpoint. Point it at the public test endpoint with
|
|
61
|
+
`--endpoint test`, switch to YAML output with `--format yaml`, or log HTTP requests and responses
|
|
62
|
+
with `--trace`:
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
skodactl --api-key XXX --endpoint test get-vehicle-status TMBJX7NY4PM054321
|
|
66
|
+
SKODA_API_KEY=XXX skodactl --format yaml --trace get-charging TMBJX7NY4PM054321
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Remote operations can be started as well:
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
skodactl --api-key XXX start-air-conditioning TMBJX7NY4PM054321 --temperature 21
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Run `skodactl --help` for the full list of commands and options.
|
|
76
|
+
|
|
77
|
+
## Development
|
|
78
|
+
|
|
79
|
+
Clone the repository and install it in editable mode together with the test dependencies:
|
|
80
|
+
|
|
81
|
+
```sh
|
|
82
|
+
pip install -e ".[test,cli]"
|
|
83
|
+
pytest
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
Distributed under the MIT License. See [`LICENSE`](LICENSE) for details.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "skoda-public-api"
|
|
7
|
+
version = "1.1.1"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Mobility Lab, VŠB-TUO" },
|
|
10
|
+
{ name = "TomVSB", email = "tomas.mrovec@vsb.cz" },
|
|
11
|
+
{ name="net0045", email="stepan.netolicky@vsb.cz" },
|
|
12
|
+
{ name="mag0051", email="david.magyarics@vsb.cz" },
|
|
13
|
+
]
|
|
14
|
+
maintainers = [
|
|
15
|
+
{ name="mag0051", email="david.magyarics@vsb.cz" },
|
|
16
|
+
{ name = "TomVSB", email = "tomas.mrovec@vsb.cz" },
|
|
17
|
+
]
|
|
18
|
+
description = "Asynchronous Python library for the Škoda public API"
|
|
19
|
+
readme = "README.md"
|
|
20
|
+
requires-python = ">=3.11"
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Framework :: AsyncIO",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"aiohttp>=3.9.0",
|
|
29
|
+
"pydantic>=2.5.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
"Homepage" = "https://github.com/mobility-lab-vsb/skoda-public-api"
|
|
34
|
+
"Bug Tracker" = "https://github.com/mobility-lab-vsb/skoda-public-api/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
skodactl = "skoda_public_api.cli:cli"
|
|
38
|
+
|
|
39
|
+
[tool.pytest.ini_options]
|
|
40
|
+
pythonpath = ["src/skoda_public_api"]
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
test = [
|
|
44
|
+
"pytest>=9.0.0",
|
|
45
|
+
"pytest-asyncio>=0.23.0",
|
|
46
|
+
"aresponses>=3.0.0",
|
|
47
|
+
]
|
|
48
|
+
cli = [
|
|
49
|
+
"asyncclick ~=8.1",
|
|
50
|
+
"coloredlogs ~=15.0",
|
|
51
|
+
"pygments ~=2.18",
|
|
52
|
+
"pyyaml ~=6.0",
|
|
53
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
SANDBOX_BASE_URL = "https://developer.sandbox.connect.skoda-auto.cz"
|
|
4
|
+
PRODUCTION_BASE_URL = "https://developer.connect.skoda-auto.cz"
|
|
5
|
+
TEST_BASE_URL = "https://public.test-api.connect.skoda-auto.cz"
|
|
6
|
+
BETA_URL = "https://public.api.connect.skoda-auto.cz"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Endpoints(StrEnum):
|
|
10
|
+
PRODUCTION = "production"
|
|
11
|
+
SANDBOX = "sandbox"
|
|
12
|
+
TEST = "test"
|
|
13
|
+
BETA = "beta"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def url(self) -> str:
|
|
17
|
+
return ENDPOINT_URLS[self]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ENDPOINT_URLS = {
|
|
21
|
+
Endpoints.PRODUCTION: PRODUCTION_BASE_URL,
|
|
22
|
+
Endpoints.SANDBOX: SANDBOX_BASE_URL,
|
|
23
|
+
Endpoints.TEST: TEST_BASE_URL,
|
|
24
|
+
Endpoints.BETA: BETA_URL,
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class OpenApiError(Exception):
|
|
5
|
+
"""Obecná chyba při komunikaci se Škoda API."""
|
|
6
|
+
def __init__(self, message: str, status_code: Optional[int] = None) -> None:
|
|
7
|
+
super().__init__(message)
|
|
8
|
+
self.status_code = status_code
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OpenApiAuthenticationError(OpenApiError):
|
|
12
|
+
"""Error 401 - Invalid or Expired X-API-Key."""
|
|
13
|
+
def __init__(self, message: str = "Invalid or expired X-API-Key.") -> None:
|
|
14
|
+
super().__init__(message, status_code=401)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OpenApiForbiddenError(OpenApiError):
|
|
18
|
+
"""Error 403 - Forbidden access to the requested resource."""
|
|
19
|
+
def __init__(self, message: str = "Access to the requested resource is forbidden.") -> None:
|
|
20
|
+
super().__init__(message, status_code=403)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OpenApiVehicleNotFoundError(OpenApiError):
|
|
24
|
+
"""Error 404 - Vehicle with this VIN does not exist."""
|
|
25
|
+
def __init__(self, message: str = "Vehicle with this VIN does not exist.") -> None:
|
|
26
|
+
super().__init__(message, status_code=404)
|
|
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)
|
|
32
|
+
|
|
33
|
+
class OpenApiRateLimitError(OpenApiError):
|
|
34
|
+
"""Error 429 - Rate limit exceeded or weak 12V battery."""
|
|
35
|
+
def __init__(self, message: str = "Rate limit exceeded or weak 12V battery.") -> None:
|
|
36
|
+
super().__init__(message, status_code=429)
|
|
37
|
+
|
|
38
|
+
class OpenApiServerError(OpenApiError):
|
|
39
|
+
"""Error 500 - Server error or timeout."""
|
|
40
|
+
def __init__(self, message: str, status_code: int = 500) -> None:
|
|
41
|
+
super().__init__(message, status_code=status_code)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, Optional, List
|
|
3
|
+
from aiohttp import ClientSession
|
|
4
|
+
from .const import BETA_URL
|
|
5
|
+
from .rest_api import PostEndpointResult, SkodaRestAPI
|
|
6
|
+
from ..models.vehicle import VehicleResponse, Odometer
|
|
7
|
+
from ..models.vehicle_status import VehicleStatus
|
|
8
|
+
from ..models.active_ventilation import ActiveVentilation
|
|
9
|
+
from ..models.air_conditioning import AirConditioning
|
|
10
|
+
from ..models.parking_position import ParkingPosition
|
|
11
|
+
from ..models.auxiliary_heating import AuxiliaryHeating
|
|
12
|
+
from ..models.charging import Charging
|
|
13
|
+
from ..models.driving_range import FuelStatus
|
|
14
|
+
from ..models.charging_profiles import ChargingProfiles
|
|
15
|
+
from ..models.configurations import StartAirConditioningConfiguration, StartAuxiliaryHeatingConfiguration, ConfigurationTargetTemperature
|
|
16
|
+
|
|
17
|
+
class OpenAPIClient:
|
|
18
|
+
"""Client for interacting with rest API and used in HomeAssistant."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, api_key: str, session: ClientSession, base_url: str = BETA_URL) -> None:
|
|
21
|
+
self.rest_api = SkodaRestAPI(api_key=api_key, session=session, base_url=base_url)
|
|
22
|
+
self.last_headers: dict[str, Any] = {}
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def api_key_expires_at(self) -> Optional[str]:
|
|
26
|
+
"""Return the expiration timestamp of the API key."""
|
|
27
|
+
return self.last_headers.get("x-api-key-expires-at")
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def rate_limit_remaining(self) -> Optional[int]:
|
|
31
|
+
"""Return remaining requests quota."""
|
|
32
|
+
val = self.last_headers.get("ratelimit-remaining")
|
|
33
|
+
return int(val) if val is not None else None
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def rate_limit_reset(self) -> Optional[int]:
|
|
37
|
+
"""Return the time when the rate limit will be reset."""
|
|
38
|
+
val = self.last_headers.get("ratelimit-reset")
|
|
39
|
+
return int(val) if val is not None else None
|
|
40
|
+
|
|
41
|
+
async def get_vehicle(self, vin: str, include: Optional[List[str]] = None) -> VehicleResponse:
|
|
42
|
+
"""Get the actual vehicle data and return the parsed Pydantic model."""
|
|
43
|
+
endpoint_result = await self.rest_api.get_vehicle(vin, include=include)
|
|
44
|
+
self.last_headers = endpoint_result.headers
|
|
45
|
+
return endpoint_result.result
|
|
46
|
+
|
|
47
|
+
async def get_vehicle_status(self, vin: str) -> Optional[VehicleStatus]:
|
|
48
|
+
endpoint_result = await self.rest_api.get_vehicle_status(vin)
|
|
49
|
+
self.last_headers = endpoint_result.headers
|
|
50
|
+
return endpoint_result.result
|
|
51
|
+
|
|
52
|
+
async def get_air_conditioning(self, vin: str) -> AirConditioning:
|
|
53
|
+
"""Get the actual vehicle status and return the parsed Pydantic model."""
|
|
54
|
+
endpoint_result = await self.rest_api.get_air_conditioning(vin)
|
|
55
|
+
self.last_headers = endpoint_result.headers
|
|
56
|
+
return endpoint_result.result
|
|
57
|
+
|
|
58
|
+
async def get_parking_positions(self, vin: str) -> ParkingPosition:
|
|
59
|
+
"""Get the actual vehicle status and return the parsed Pydantic model."""
|
|
60
|
+
endpoint_result = await self.rest_api.get_parking_positions(vin)
|
|
61
|
+
self.last_headers = endpoint_result.headers
|
|
62
|
+
return endpoint_result.result
|
|
63
|
+
|
|
64
|
+
async def get_auxiliary_heating(self, vin: str) -> AuxiliaryHeating:
|
|
65
|
+
"""Get the actual vehicle status and return the parsed Pydantic model."""
|
|
66
|
+
endpoint_result = await self.rest_api.get_auxiliary_heating(vin)
|
|
67
|
+
self.last_headers = endpoint_result.headers
|
|
68
|
+
return endpoint_result.result
|
|
69
|
+
|
|
70
|
+
async def get_odometer(self, vin: str) -> Odometer:
|
|
71
|
+
"""Get the actual vehicle status and return the parsed Pydantic model."""
|
|
72
|
+
endpoint_result = await self.rest_api.get_odometer(vin)
|
|
73
|
+
self.last_headers = endpoint_result.headers
|
|
74
|
+
return endpoint_result.result
|
|
75
|
+
|
|
76
|
+
async def get_charging(self, vin: str) -> Charging:
|
|
77
|
+
"""Get the actual vehicle status and return the parsed Pydantic model."""
|
|
78
|
+
endpoint_result = await self.rest_api.get_charging(vin)
|
|
79
|
+
self.last_headers = endpoint_result.headers
|
|
80
|
+
return endpoint_result.result
|
|
81
|
+
|
|
82
|
+
async def get_active_ventilation(self, vin: str) -> ActiveVentilation:
|
|
83
|
+
"""Get the actual active ventilation and return the parsed Pydantic model."""
|
|
84
|
+
endpoint_result = await self.rest_api.get_active_ventilation(vin)
|
|
85
|
+
self.last_headers = endpoint_result.headers
|
|
86
|
+
return endpoint_result.result
|
|
87
|
+
|
|
88
|
+
async def get_fuel_status(self, vin: str) -> FuelStatus:
|
|
89
|
+
"""Get the actual fuel status and return the parsed Pydantic model."""
|
|
90
|
+
endpoint_result = await self.rest_api.get_fuel_status(vin)
|
|
91
|
+
self.last_headers = endpoint_result.headers
|
|
92
|
+
return endpoint_result.result
|
|
93
|
+
|
|
94
|
+
async def get_charging_profiles(self, vin: str) -> ChargingProfiles:
|
|
95
|
+
"""Get the actual charging profiles and return the parsed Pydantic model."""
|
|
96
|
+
endpoint_result = await self.rest_api.get_charging_profiles(vin)
|
|
97
|
+
self.last_headers = endpoint_result.headers
|
|
98
|
+
return endpoint_result.result
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def start_air_conditioning(self, vin: str, temperature: float, unit: str = "CELSIUS", without_external_power: bool = True) -> PostEndpointResult:
|
|
102
|
+
"""Starts the air conditioning for the vehicle with the given VIN."""
|
|
103
|
+
config = StartAirConditioningConfiguration(
|
|
104
|
+
target_temperature=ConfigurationTargetTemperature(
|
|
105
|
+
value=temperature,
|
|
106
|
+
unit=unit,
|
|
107
|
+
),
|
|
108
|
+
air_conditioning_without_external_power=without_external_power,
|
|
109
|
+
)
|
|
110
|
+
return await self.rest_api.start_air_conditioning(vin, config)
|
|
111
|
+
|
|
112
|
+
async def stop_air_conditioning(self, vin: str) -> PostEndpointResult:
|
|
113
|
+
"""Stops the air_conditioning of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant"""
|
|
114
|
+
return await self.rest_api.stop_air_conditioning(vin)
|
|
115
|
+
|
|
116
|
+
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") -> PostEndpointResult:
|
|
117
|
+
"""Starts the auxiliary heating for the vehicle with the given VIN."""
|
|
118
|
+
temp_obj = None
|
|
119
|
+
if target_temperature is not None:
|
|
120
|
+
temp_obj = ConfigurationTargetTemperature(
|
|
121
|
+
value=target_temperature,
|
|
122
|
+
unit=unit,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
config = StartAuxiliaryHeatingConfiguration(
|
|
126
|
+
spin=spin,
|
|
127
|
+
duration_in_seconds=duration_in_seconds,
|
|
128
|
+
start_mode=start_mode,
|
|
129
|
+
target_temperature=temp_obj,
|
|
130
|
+
)
|
|
131
|
+
return await self.rest_api.start_auxiliary_heating(vin, config)
|
|
132
|
+
|
|
133
|
+
async def stop_auxiliary_heating(self, vin: str) -> PostEndpointResult:
|
|
134
|
+
"""Stops the auxiliary_heating of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant"""
|
|
135
|
+
return await self.rest_api.stop_auxiliary_heating(vin)
|
|
136
|
+
|
|
137
|
+
async def start_active_ventilation(self, vin: str) -> PostEndpointResult:
|
|
138
|
+
"""Starts the active_ventilation for the vehicle with the given VIN."""
|
|
139
|
+
return await self.rest_api.start_active_ventilation(vin)
|
|
140
|
+
|
|
141
|
+
async def stop_active_ventilation(self, vin: str) -> PostEndpointResult:
|
|
142
|
+
"""Stops the active_ventilation of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant"""
|
|
143
|
+
return await self.rest_api.stop_active_ventilation(vin)
|
|
144
|
+
|
|
145
|
+
async def start_charging(self, vin: str) -> PostEndpointResult:
|
|
146
|
+
"""Starts the charging process for the vehicle with the given VIN."""
|
|
147
|
+
return await self.rest_api.start_charging(vin)
|
|
148
|
+
|
|
149
|
+
async def stop_charging(self, vin: str) -> PostEndpointResult:
|
|
150
|
+
"""Stops the charging process for the vehicle with the given VIN."""
|
|
151
|
+
return await self.rest_api.stop_charging(vin)
|
|
152
|
+
|
|
153
|
+
async def connect(self):
|
|
154
|
+
"""TODO: Implementation of connect mechanism."""
|
|
155
|
+
pass
|
|
156
|
+
|
|
157
|
+
async def disconnect(self) -> None:
|
|
158
|
+
"""TODO: Implementation of disconnect mechanism."""
|
|
159
|
+
pass
|
|
160
|
+
|
|
161
|
+
async def verify_spin(self, spin: str) -> bool:
|
|
162
|
+
"""TODO: Implementation of SPIN verification."""
|
|
163
|
+
pass
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
======= NOT IMPLEMENTED FUNCTIONS - CAN BE USED SOMETIME IN THE FUTURE =======
|
|
167
|
+
"""
|
|
168
|
+
async def refresh_auxiliary_heating(self, vin: str) -> None:
|
|
169
|
+
"""Refreshes the auxiliary heating status of the vehicle with the given VIN."""
|
|
170
|
+
pass
|
|
171
|
+
|
|
172
|
+
async def set_reduced_current_limit(self, vin: str) -> None:
|
|
173
|
+
"""Sets the charging current limit (e.g., to REDUCED or MAXIMUM) for the vehicle with the given VIN."""
|
|
174
|
+
pass
|
|
175
|
+
|
|
176
|
+
async def set_seats_heating(self, vin: str) -> None:
|
|
177
|
+
"""Configures the seats heating settings for the vehicle with the given VIN."""
|
|
178
|
+
pass
|
|
179
|
+
|
|
180
|
+
async def start_window_heating(self, vin: str) -> None:
|
|
181
|
+
"""Starts the electric window heating for the vehicle with the given VIN."""
|
|
182
|
+
pass
|
|
183
|
+
|
|
184
|
+
async def stop_window_heating(self, vin: str) -> None:
|
|
185
|
+
"""Stops the window heating of the vehicle and return None if it was succesfull else catch an exception in HomeAssistant."""
|
|
186
|
+
pass
|
|
187
|
+
|
|
188
|
+
async def set_windows_heating(self, vin: str) -> None:
|
|
189
|
+
"""Configures the front and rear windows heating settings for the vehicle with the given VIN."""
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
async def set_auto_unlock_plug(self, vin: str) -> None:
|
|
193
|
+
"""Sets the automatic unlocking behavior of the charging plug (e.g., PERMANENT or OFF) for the vehicle with the given VIN."""
|
|
194
|
+
pass
|
|
195
|
+
async def set_charge_limit(self, vin: str, limit: int) -> None:
|
|
196
|
+
"""Sets the maximum charging limit in percent for the vehicle with the given VIN."""
|
|
197
|
+
pass
|
|
198
|
+
|
|
199
|
+
async def set_target_temperature(self, vin: str, temperature: float) -> None:
|
|
200
|
+
"""Sets the target temperature for AC or auxiliary heating for the vehicle with the given VIN."""
|
|
201
|
+
pass
|
|
202
|
+
# TODO: Add more methods for other endpoints as needed
|