pytoyoda 2.3.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.
- pytoyoda-2.3.1/LICENSE +21 -0
- pytoyoda-2.3.1/PKG-INFO +98 -0
- pytoyoda-2.3.1/README.md +67 -0
- pytoyoda-2.3.1/pyproject.toml +92 -0
- pytoyoda-2.3.1/pytoyoda/__init__.py +6 -0
- pytoyoda-2.3.1/pytoyoda/api.py +272 -0
- pytoyoda-2.3.1/pytoyoda/client.py +67 -0
- pytoyoda-2.3.1/pytoyoda/const.py +20 -0
- pytoyoda-2.3.1/pytoyoda/controller.py +304 -0
- pytoyoda-2.3.1/pytoyoda/exceptions.py +25 -0
- pytoyoda-2.3.1/pytoyoda/models/dashboard.py +221 -0
- pytoyoda-2.3.1/pytoyoda/models/electric_status.py +120 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/account.py +81 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/common.py +51 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/electric.py +57 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/location.py +50 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/notifications.py +70 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/service_history.py +70 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/status.py +89 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/telemetry.py +43 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/trips.py +215 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/vehicle_guid.py +467 -0
- pytoyoda-2.3.1/pytoyoda/models/endpoints/vehicle_health.py +44 -0
- pytoyoda-2.3.1/pytoyoda/models/location.py +69 -0
- pytoyoda-2.3.1/pytoyoda/models/lock_status.py +273 -0
- pytoyoda-2.3.1/pytoyoda/models/nofication.py +82 -0
- pytoyoda-2.3.1/pytoyoda/models/service_history.py +140 -0
- pytoyoda-2.3.1/pytoyoda/models/summary.py +193 -0
- pytoyoda-2.3.1/pytoyoda/models/trips.py +196 -0
- pytoyoda-2.3.1/pytoyoda/models/vehicle.py +566 -0
- pytoyoda-2.3.1/pytoyoda/py.typed +0 -0
- pytoyoda-2.3.1/pytoyoda/utils/__init__.py +1 -0
- pytoyoda-2.3.1/pytoyoda/utils/conversions.py +37 -0
- pytoyoda-2.3.1/pytoyoda/utils/formatters.py +12 -0
- pytoyoda-2.3.1/pytoyoda/utils/helpers.py +14 -0
- pytoyoda-2.3.1/pytoyoda/utils/locale.py +15 -0
- pytoyoda-2.3.1/pytoyoda/utils/log_utils.py +152 -0
- pytoyoda-2.3.1/pytoyoda/utils/models.py +25 -0
pytoyoda-2.3.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Simon Hansen
|
|
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.
|
pytoyoda-2.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pytoyoda
|
|
3
|
+
Version: 2.3.1
|
|
4
|
+
Summary: Python client for Toyota Connected Services.
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: Toyota,Car,MYT
|
|
7
|
+
Author: Simon Grud Hansen
|
|
8
|
+
Author-email: simongrud@gmail.com
|
|
9
|
+
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Dist: arrow (>=1.1,<2.0)
|
|
19
|
+
Requires-Dist: hishel (>=0.0.19,<0.0.20)
|
|
20
|
+
Requires-Dist: httpx (>=0.18.1)
|
|
21
|
+
Requires-Dist: importlib-metadata (>=7.0.1,<8.0.0)
|
|
22
|
+
Requires-Dist: langcodes (>=3.1,<4.0)
|
|
23
|
+
Requires-Dist: pydantic (>=2.10.4,<3.0.0)
|
|
24
|
+
Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
|
|
25
|
+
Project-URL: Bug Tracker, https://github.com/pytoyoda/pytoyoda/issues
|
|
26
|
+
Project-URL: Homepage, https://github.com/pytoyoda/pytoyoda
|
|
27
|
+
Project-URL: Repository, https://github.com/pytoyoda/pytoyoda
|
|
28
|
+
Project-URL: Release Notes, https://github.com/pytoyoda/pytoyoda/releases
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+

|
|
32
|
+

|
|
33
|
+

|
|
34
|
+

|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
# Toyota Connected Services Europe Python module
|
|
38
|
+
|
|
39
|
+
<b><p align=center> 🚨 Breaking changes ahead 🚨 </p></b>
|
|
40
|
+
|
|
41
|
+
<p align=center> Version 1.0.0 only supports the new ctpa-oneapi API endpoints that were introduced with the new MyToyota app. Some functions are not yet implemented and must first be determined due to the lack of API documentation. </p>
|
|
42
|
+
<p align=center> Users of the old MyT app should use a mytoyota python module version < 1.0.0. </p>
|
|
43
|
+
|
|
44
|
+
⚠️ _This is still in beta_
|
|
45
|
+
|
|
46
|
+
⚠️ _Only EU is supported, other regions are not possible so far. See [this](https://github.com/widewing/toyota-na) for North America_
|
|
47
|
+
|
|
48
|
+
## Description
|
|
49
|
+
|
|
50
|
+
Python 3 package to communicate with [Toyota Connected Europe](https://www.toyota-europe.com/about-us/toyota-in-europe/toyota-connected-europe) Services.
|
|
51
|
+
This is an unofficial package and Toyota can change their API at any point without warning.
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
This package can be installed through `pip`.
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
pip install pytoyoda
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
For a quick start on how to use the package take a look at the `simple_client_example.py` file contained in the report. You can also use and execute this file directly by using the following commands:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
python -m venv pytoyoda
|
|
67
|
+
source pytoyoda/bin/activate
|
|
68
|
+
python -m pip install "pytoyoda@git+https://github.com/pytoyoda/pytoyoda@main"
|
|
69
|
+
curl -LO https://raw.githubusercontent.com/pytoyoda/pytoyoda/main/simple_client_example.py
|
|
70
|
+
# Create a credentials.json file with {"username":"your@mail.tld","password":"yourpassword"}
|
|
71
|
+
python simple_client_example.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Known issues
|
|
75
|
+
|
|
76
|
+
- Statistical endpoint will return `None` if no trip have been performed in the requested timeframe. This problem will often happen at the start of each week, month or year. Also daily stats will of course also be unavailable if no trip have been performed.
|
|
77
|
+
- Currently, it is only possible to get various vehicle information. Functions for controlling and setting vehicle properties have not yet been implemented.
|
|
78
|
+
|
|
79
|
+
## Docs
|
|
80
|
+
|
|
81
|
+
Coming soon...
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
This python module uses poetry (>= 2.0.0) and pre-commit.
|
|
86
|
+
|
|
87
|
+
To start contributing, fork this repository and run `poetry install`. Then create a new branch. Before making a PR, please run pre-commit `poetry run pre-commit run --all-files` and make sure that all tests passes locally first by running `pytest tests/`.
|
|
88
|
+
|
|
89
|
+
## Note
|
|
90
|
+
|
|
91
|
+
This is a friendly community fork of the original project by [@DurgNomis-drol](https://github.com/DurgNomis-drol),
|
|
92
|
+
to ease up on maintenance and the [bus factor](https://en.wikipedia.org/wiki/Bus_factor) for this project.
|
|
93
|
+
|
|
94
|
+
## Credits
|
|
95
|
+
|
|
96
|
+
Special thanks go [@DurgNomis-drol](https://github.com/DurgNomis-drol) for starting this project!
|
|
97
|
+
A huge thanks go to [@calmjm](https://github.com/calmjm) for making [tojota](https://github.com/calmjm/tojota).
|
|
98
|
+
|
pytoyoda-2.3.1/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
# Toyota Connected Services Europe Python module
|
|
8
|
+
|
|
9
|
+
<b><p align=center> 🚨 Breaking changes ahead 🚨 </p></b>
|
|
10
|
+
|
|
11
|
+
<p align=center> Version 1.0.0 only supports the new ctpa-oneapi API endpoints that were introduced with the new MyToyota app. Some functions are not yet implemented and must first be determined due to the lack of API documentation. </p>
|
|
12
|
+
<p align=center> Users of the old MyT app should use a mytoyota python module version < 1.0.0. </p>
|
|
13
|
+
|
|
14
|
+
⚠️ _This is still in beta_
|
|
15
|
+
|
|
16
|
+
⚠️ _Only EU is supported, other regions are not possible so far. See [this](https://github.com/widewing/toyota-na) for North America_
|
|
17
|
+
|
|
18
|
+
## Description
|
|
19
|
+
|
|
20
|
+
Python 3 package to communicate with [Toyota Connected Europe](https://www.toyota-europe.com/about-us/toyota-in-europe/toyota-connected-europe) Services.
|
|
21
|
+
This is an unofficial package and Toyota can change their API at any point without warning.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
This package can be installed through `pip`.
|
|
26
|
+
|
|
27
|
+
```text
|
|
28
|
+
pip install pytoyoda
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
For a quick start on how to use the package take a look at the `simple_client_example.py` file contained in the report. You can also use and execute this file directly by using the following commands:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python -m venv pytoyoda
|
|
37
|
+
source pytoyoda/bin/activate
|
|
38
|
+
python -m pip install "pytoyoda@git+https://github.com/pytoyoda/pytoyoda@main"
|
|
39
|
+
curl -LO https://raw.githubusercontent.com/pytoyoda/pytoyoda/main/simple_client_example.py
|
|
40
|
+
# Create a credentials.json file with {"username":"your@mail.tld","password":"yourpassword"}
|
|
41
|
+
python simple_client_example.py
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Known issues
|
|
45
|
+
|
|
46
|
+
- Statistical endpoint will return `None` if no trip have been performed in the requested timeframe. This problem will often happen at the start of each week, month or year. Also daily stats will of course also be unavailable if no trip have been performed.
|
|
47
|
+
- Currently, it is only possible to get various vehicle information. Functions for controlling and setting vehicle properties have not yet been implemented.
|
|
48
|
+
|
|
49
|
+
## Docs
|
|
50
|
+
|
|
51
|
+
Coming soon...
|
|
52
|
+
|
|
53
|
+
## Contributing
|
|
54
|
+
|
|
55
|
+
This python module uses poetry (>= 2.0.0) and pre-commit.
|
|
56
|
+
|
|
57
|
+
To start contributing, fork this repository and run `poetry install`. Then create a new branch. Before making a PR, please run pre-commit `poetry run pre-commit run --all-files` and make sure that all tests passes locally first by running `pytest tests/`.
|
|
58
|
+
|
|
59
|
+
## Note
|
|
60
|
+
|
|
61
|
+
This is a friendly community fork of the original project by [@DurgNomis-drol](https://github.com/DurgNomis-drol),
|
|
62
|
+
to ease up on maintenance and the [bus factor](https://en.wikipedia.org/wiki/Bus_factor) for this project.
|
|
63
|
+
|
|
64
|
+
## Credits
|
|
65
|
+
|
|
66
|
+
Special thanks go [@DurgNomis-drol](https://github.com/DurgNomis-drol) for starting this project!
|
|
67
|
+
A huge thanks go to [@calmjm](https://github.com/calmjm) for making [tojota](https://github.com/calmjm/tojota).
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "pytoyoda"
|
|
3
|
+
description = "Python client for Toyota Connected Services."
|
|
4
|
+
authors = ["Simon Grud Hansen <simongrud@gmail.com>"]
|
|
5
|
+
license = "MIT"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
version = "2.3.1"
|
|
8
|
+
packages = [
|
|
9
|
+
{ include = "pytoyoda" },
|
|
10
|
+
]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3.9",
|
|
15
|
+
"Programming Language :: Python :: 3.10",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
18
|
+
]
|
|
19
|
+
keywords = [
|
|
20
|
+
"Toyota",
|
|
21
|
+
"Car",
|
|
22
|
+
"MYT",
|
|
23
|
+
]
|
|
24
|
+
homepage = "https://github.com/pytoyoda/pytoyoda"
|
|
25
|
+
repository = "https://github.com/pytoyoda/pytoyoda"
|
|
26
|
+
|
|
27
|
+
[tool.poetry.urls]
|
|
28
|
+
"Bug Tracker" = "https://github.com/pytoyoda/pytoyoda/issues"
|
|
29
|
+
"Release Notes" = "https://github.com/pytoyoda/pytoyoda/releases"
|
|
30
|
+
|
|
31
|
+
# Automatic installation of plugins fails due to https://github.com/python-poetry/poetry/issues/10028
|
|
32
|
+
# so we still do a `self add`
|
|
33
|
+
#[tool.poetry.requires-plugins]
|
|
34
|
+
#poetry-dynamic-versioning = { version = ">=1.0.0,<2.0.0", extras = ["plugin"] }
|
|
35
|
+
|
|
36
|
+
[tool.poetry.dependencies]
|
|
37
|
+
python = "^3.9"
|
|
38
|
+
langcodes = "^3.1"
|
|
39
|
+
httpx = ">=0.18.1"
|
|
40
|
+
arrow = "^1.1"
|
|
41
|
+
importlib-metadata = "^7.0.1"
|
|
42
|
+
pyjwt = "^2.8.0"
|
|
43
|
+
pydantic = "^2.10.4"
|
|
44
|
+
hishel = "^0.0.19"
|
|
45
|
+
|
|
46
|
+
[tool.poetry.dev-dependencies]
|
|
47
|
+
pre-commit = "^3.0.0"
|
|
48
|
+
pre-commit-hooks = "^4.5.0"
|
|
49
|
+
ruff = "^0.1.9"
|
|
50
|
+
codespell = "^2.0.0"
|
|
51
|
+
pytest = "^7.2.0"
|
|
52
|
+
pytest-pretty = "^1.2.0"
|
|
53
|
+
pytest-asyncio = "^0.21.1"
|
|
54
|
+
pytest-httpx = "^0.28.0"
|
|
55
|
+
|
|
56
|
+
[tool.ruff]
|
|
57
|
+
select = [
|
|
58
|
+
# Ruff specific
|
|
59
|
+
"RUF",
|
|
60
|
+
# Pylint
|
|
61
|
+
"PL",
|
|
62
|
+
# Pyflakes
|
|
63
|
+
"F",
|
|
64
|
+
# pep8-naming
|
|
65
|
+
"N",
|
|
66
|
+
# Pycodestyle
|
|
67
|
+
"E",
|
|
68
|
+
"W",
|
|
69
|
+
"D",
|
|
70
|
+
# flake8-2020
|
|
71
|
+
"YTT",
|
|
72
|
+
# flake8-async
|
|
73
|
+
"ASYNC",
|
|
74
|
+
# flake8-bugbear
|
|
75
|
+
"B",
|
|
76
|
+
# flake8-unused-arguments
|
|
77
|
+
"ARG",
|
|
78
|
+
# flake8-commas
|
|
79
|
+
"COM",
|
|
80
|
+
# Isort
|
|
81
|
+
"I"
|
|
82
|
+
]
|
|
83
|
+
extend-ignore = ["PLR2004", "D203", "D213", "COM812"]
|
|
84
|
+
line-length = 99
|
|
85
|
+
fix = true
|
|
86
|
+
|
|
87
|
+
[tool.poetry-dynamic-versioning]
|
|
88
|
+
enable = false
|
|
89
|
+
|
|
90
|
+
[build-system]
|
|
91
|
+
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
|
|
92
|
+
build-backend = "poetry_dynamic_versioning.backend"
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""Toyota Connected Services API."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from datetime import date, datetime, timezone
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from pytoyoda.const import (
|
|
8
|
+
VEHICLE_ASSOCIATION_ENDPOINT,
|
|
9
|
+
VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT,
|
|
10
|
+
VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT,
|
|
11
|
+
VEHICLE_GUID_ENDPOINT,
|
|
12
|
+
VEHICLE_HEALTH_STATUS_ENDPOINT,
|
|
13
|
+
VEHICLE_LOCATION_ENDPOINT,
|
|
14
|
+
VEHICLE_NOTIFICATION_HISTORY_ENDPOINT,
|
|
15
|
+
VEHICLE_SERVICE_HISTORY_ENDPONT,
|
|
16
|
+
VEHICLE_TELEMETRY_ENDPOINT,
|
|
17
|
+
VEHICLE_TRIPS_ENDPOINT,
|
|
18
|
+
)
|
|
19
|
+
from pytoyoda.controller import Controller
|
|
20
|
+
from pytoyoda.models.endpoints.electric import ElectricResponseModel
|
|
21
|
+
from pytoyoda.models.endpoints.location import LocationResponseModel
|
|
22
|
+
from pytoyoda.models.endpoints.notifications import NotificationResponseModel
|
|
23
|
+
from pytoyoda.models.endpoints.service_history import ServiceHistoryResponseModel
|
|
24
|
+
from pytoyoda.models.endpoints.status import RemoteStatusResponseModel
|
|
25
|
+
from pytoyoda.models.endpoints.telemetry import TelemetryResponseModel
|
|
26
|
+
from pytoyoda.models.endpoints.trips import TripsResponseModel
|
|
27
|
+
from pytoyoda.models.endpoints.vehicle_guid import VehiclesResponseModel
|
|
28
|
+
from pytoyoda.models.endpoints.vehicle_health import VehicleHealthResponseModel
|
|
29
|
+
|
|
30
|
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class Api:
|
|
34
|
+
"""API Class. Allows access to available endpoints to retrieve the raw data."""
|
|
35
|
+
|
|
36
|
+
def __init__(self, controller: Controller) -> None:
|
|
37
|
+
"""Initialise the API.
|
|
38
|
+
|
|
39
|
+
Initialise the API and set the Controller
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
----
|
|
43
|
+
controller: Controller: A controller class to managing communication
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
-------
|
|
47
|
+
None
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
self.controller = controller
|
|
51
|
+
|
|
52
|
+
async def _request_and_parse(self, model, method: str, endpoint: str, **kwargs):
|
|
53
|
+
"""Parse requests and responses."""
|
|
54
|
+
response = await self.controller.request_json(method=method, endpoint=endpoint, **kwargs)
|
|
55
|
+
return model(**response)
|
|
56
|
+
|
|
57
|
+
async def set_vehicle_alias_endpoint(self, alias: str, guid: str, vin: str):
|
|
58
|
+
"""Set the alias for a vehicle."""
|
|
59
|
+
return await self.controller.request_raw(
|
|
60
|
+
method="PUT",
|
|
61
|
+
endpoint=VEHICLE_ASSOCIATION_ENDPOINT,
|
|
62
|
+
vin=vin,
|
|
63
|
+
headers={
|
|
64
|
+
"datetime": str(int(datetime.now(timezone.utc).timestamp() * 1000)),
|
|
65
|
+
"x-correlationid": str(uuid4()),
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
},
|
|
68
|
+
body={"guid": guid, "vin": vin, "nickName": alias},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# TODO: Remove for now as it seems to have no effect.
|
|
72
|
+
# The App is sending it!
|
|
73
|
+
# async def post_wake_endpoint(self) -> None:
|
|
74
|
+
# """Send a wake request to the vehicle."""
|
|
75
|
+
# await self.controller.request_raw(
|
|
76
|
+
# method="POST", endpoint="/v2/global/remote/wake"
|
|
77
|
+
# )
|
|
78
|
+
|
|
79
|
+
async def get_vehicles_endpoint(self) -> VehiclesResponseModel:
|
|
80
|
+
"""Return list of vehicles registered with provider."""
|
|
81
|
+
parsed_response = await self._request_and_parse(
|
|
82
|
+
VehiclesResponseModel, "GET", VEHICLE_GUID_ENDPOINT
|
|
83
|
+
)
|
|
84
|
+
_LOGGER.debug(msg=f"Parsed 'VehiclesResponseModel': {parsed_response}")
|
|
85
|
+
return parsed_response
|
|
86
|
+
|
|
87
|
+
async def get_location_endpoint(self, vin: str) -> LocationResponseModel:
|
|
88
|
+
"""Get the last known location of your car. Only updates when car is parked.
|
|
89
|
+
|
|
90
|
+
Response includes Lat, Lon position. * If supported.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
----
|
|
94
|
+
vin: str: The vehicles VIN
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
-------
|
|
98
|
+
LocationResponseModel: A pydantic model for the location response
|
|
99
|
+
|
|
100
|
+
"""
|
|
101
|
+
parsed_response = await self._request_and_parse(
|
|
102
|
+
LocationResponseModel, "GET", VEHICLE_LOCATION_ENDPOINT, vin=vin
|
|
103
|
+
)
|
|
104
|
+
_LOGGER.debug(msg=f"Parsed 'LocationResponseModel': {parsed_response}")
|
|
105
|
+
return parsed_response
|
|
106
|
+
|
|
107
|
+
async def get_vehicle_health_status_endpoint(self, vin: str) -> VehicleHealthResponseModel:
|
|
108
|
+
r"""Get the latest health status.
|
|
109
|
+
|
|
110
|
+
Response includes the quantity of engine oil and any dashboard warning lights. \n
|
|
111
|
+
* If supported.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
----
|
|
115
|
+
vin: str: The vehicles VIN
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
-------
|
|
119
|
+
VehicleHealthResponseModel: A pydantic model for the vehicle health response
|
|
120
|
+
|
|
121
|
+
"""
|
|
122
|
+
parsed_response = await self._request_and_parse(
|
|
123
|
+
VehicleHealthResponseModel, "GET", VEHICLE_HEALTH_STATUS_ENDPOINT, vin=vin
|
|
124
|
+
)
|
|
125
|
+
_LOGGER.debug(msg=f"Parsed 'VehicleHealthResponseModel': {parsed_response}")
|
|
126
|
+
return parsed_response
|
|
127
|
+
|
|
128
|
+
async def get_remote_status_endpoint(self, vin: str) -> RemoteStatusResponseModel:
|
|
129
|
+
"""Get information about the vehicle."""
|
|
130
|
+
parsed_response = await self._request_and_parse(
|
|
131
|
+
RemoteStatusResponseModel,
|
|
132
|
+
"GET",
|
|
133
|
+
VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT,
|
|
134
|
+
vin=vin,
|
|
135
|
+
)
|
|
136
|
+
_LOGGER.debug(msg=f"Parsed 'RemoteStatusResponseModel': {parsed_response}")
|
|
137
|
+
return parsed_response
|
|
138
|
+
|
|
139
|
+
async def get_vehicle_electric_status_endpoint(self, vin: str) -> ElectricResponseModel:
|
|
140
|
+
r"""Get the latest electric status.
|
|
141
|
+
|
|
142
|
+
Response includes current battery level, EV Range, EV Range with AC, \n
|
|
143
|
+
fuel level, fuel range and current charging status
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
----
|
|
147
|
+
vin: str: The vehicles VIN
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
-------
|
|
151
|
+
ElectricResponseModel: A pydantic model for the electric response
|
|
152
|
+
|
|
153
|
+
"""
|
|
154
|
+
parsed_response = await self._request_and_parse(
|
|
155
|
+
ElectricResponseModel,
|
|
156
|
+
"GET",
|
|
157
|
+
VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT,
|
|
158
|
+
vin=vin,
|
|
159
|
+
)
|
|
160
|
+
_LOGGER.debug(msg=f"Parsed 'ElectricResponseModel': {parsed_response}")
|
|
161
|
+
return parsed_response
|
|
162
|
+
|
|
163
|
+
async def get_telemetry_endpoint(self, vin: str) -> TelemetryResponseModel:
|
|
164
|
+
"""Get the latest telemetry status.
|
|
165
|
+
|
|
166
|
+
Response includes current fuel level, distance to empty and odometer
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
----
|
|
170
|
+
vin: str: The vehicles VIN
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
-------
|
|
174
|
+
TelemetryResponseModel: A pydantic model for the telemetry response
|
|
175
|
+
|
|
176
|
+
"""
|
|
177
|
+
parsed_response = await self._request_and_parse(
|
|
178
|
+
TelemetryResponseModel, "GET", VEHICLE_TELEMETRY_ENDPOINT, vin=vin
|
|
179
|
+
)
|
|
180
|
+
_LOGGER.debug(msg=f"Parsed 'TelemetryResponseModel': {parsed_response}")
|
|
181
|
+
return parsed_response
|
|
182
|
+
|
|
183
|
+
async def get_notification_endpoint(self, vin: str) -> NotificationResponseModel:
|
|
184
|
+
"""Get all available notifications for the vehicle.
|
|
185
|
+
|
|
186
|
+
A notification includes a message, notification date, read flag, date read.
|
|
187
|
+
|
|
188
|
+
NOTE: Currently no way to mark notification as read or limit the response.
|
|
189
|
+
|
|
190
|
+
Args:
|
|
191
|
+
----
|
|
192
|
+
vin: str: The vehicles VIN
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
-------
|
|
196
|
+
NotificationResponseModel: A pydantic model for the notification response
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
parsed_response = await self._request_and_parse(
|
|
200
|
+
NotificationResponseModel,
|
|
201
|
+
"GET",
|
|
202
|
+
VEHICLE_NOTIFICATION_HISTORY_ENDPOINT,
|
|
203
|
+
vin=vin,
|
|
204
|
+
)
|
|
205
|
+
_LOGGER.debug(msg=f"Parsed 'NotificationResponseModel': {parsed_response}")
|
|
206
|
+
return parsed_response
|
|
207
|
+
|
|
208
|
+
async def get_trips_endpoint( # noqa: PLR0913
|
|
209
|
+
self,
|
|
210
|
+
vin: str,
|
|
211
|
+
from_date: date,
|
|
212
|
+
to_date: date,
|
|
213
|
+
route: bool = False,
|
|
214
|
+
summary: bool = True,
|
|
215
|
+
limit: int = 5,
|
|
216
|
+
offset: int = 0,
|
|
217
|
+
) -> TripsResponseModel:
|
|
218
|
+
r"""Get list of trips.
|
|
219
|
+
|
|
220
|
+
Retrieves a list of all trips between the given dates. \n
|
|
221
|
+
The default data(route = False, summary = False) provides
|
|
222
|
+
a basic summary of each trip and includes Coaching message and electrical use.
|
|
223
|
+
|
|
224
|
+
Args:
|
|
225
|
+
----
|
|
226
|
+
vin: str: The vehicles VIN
|
|
227
|
+
from_date: date: From date to include trips, inclusive. Cant be in the future.
|
|
228
|
+
to_date: date: To date to include trips, inclusive. Cant be in the future.
|
|
229
|
+
route: bool: If true returns the route of each trip as a list of coordinates.
|
|
230
|
+
Suitable for drawing on a map.
|
|
231
|
+
summary: bool: If true returns a summary of each month and day in the date range
|
|
232
|
+
limit: int: Limit of number of trips to return in one request. Max 50.
|
|
233
|
+
offset: int: Offset into trips to start the request.
|
|
234
|
+
|
|
235
|
+
Returns:
|
|
236
|
+
-------
|
|
237
|
+
TripsResponseModel: A pydantic model for the trips response
|
|
238
|
+
|
|
239
|
+
"""
|
|
240
|
+
endpoint = VEHICLE_TRIPS_ENDPOINT.format(
|
|
241
|
+
from_date=from_date,
|
|
242
|
+
to_date=to_date,
|
|
243
|
+
route=route,
|
|
244
|
+
summary=summary,
|
|
245
|
+
limit=limit,
|
|
246
|
+
offset=offset,
|
|
247
|
+
)
|
|
248
|
+
parsed_response = await self._request_and_parse(
|
|
249
|
+
TripsResponseModel, "GET", endpoint, vin=vin
|
|
250
|
+
)
|
|
251
|
+
_LOGGER.debug(msg=f"Parsed 'TripsResponseModel': {parsed_response}")
|
|
252
|
+
return parsed_response
|
|
253
|
+
|
|
254
|
+
async def get_service_history_endpoint(self, vin: str) -> ServiceHistoryResponseModel:
|
|
255
|
+
"""Get the current servic history.
|
|
256
|
+
|
|
257
|
+
Response includes service category, date and dealer.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
----
|
|
261
|
+
vin: str: The vehicles VIN
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
-------
|
|
265
|
+
ServicHistoryResponseModel: A pydantic model for the service history response
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
parsed_response = await self._request_and_parse(
|
|
269
|
+
ServiceHistoryResponseModel, "GET", VEHICLE_SERVICE_HISTORY_ENDPONT, vin=vin
|
|
270
|
+
)
|
|
271
|
+
_LOGGER.debug(msg=f"Parsed 'ServiceHistoryResponseModel': {parsed_response}")
|
|
272
|
+
return parsed_response
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Client for connecting to Toyota Connected Services.
|
|
2
|
+
|
|
3
|
+
A client for connecting to MyT (Toyota Connected Services) and retrieving vehicle
|
|
4
|
+
information, sensor data, fuel level, driving statistics and more.
|
|
5
|
+
|
|
6
|
+
Typical usage example:
|
|
7
|
+
|
|
8
|
+
client = MyT()
|
|
9
|
+
vehicles = await client.get_vehicles()
|
|
10
|
+
"""
|
|
11
|
+
import logging
|
|
12
|
+
from typing import List, Optional
|
|
13
|
+
|
|
14
|
+
from pytoyoda.api import Api
|
|
15
|
+
from pytoyoda.models.vehicle import Vehicle
|
|
16
|
+
|
|
17
|
+
from .controller import Controller
|
|
18
|
+
from .exceptions import ToyotaInvalidUsernameError
|
|
19
|
+
|
|
20
|
+
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MyT:
|
|
24
|
+
"""Connected Services client.
|
|
25
|
+
|
|
26
|
+
Connected services client class.
|
|
27
|
+
|
|
28
|
+
NOTE: Only tested with Toyota endpoints to this point.
|
|
29
|
+
Do you have a Lexus/Subaru and are willing to help?
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
username: str,
|
|
35
|
+
password: str,
|
|
36
|
+
controller_class=Controller,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Initialise Connected Services client."""
|
|
39
|
+
if username is None or "@" not in username:
|
|
40
|
+
raise ToyotaInvalidUsernameError
|
|
41
|
+
|
|
42
|
+
self._api = Api(
|
|
43
|
+
controller_class(
|
|
44
|
+
username=username,
|
|
45
|
+
password=password,
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
async def login(self) -> None:
|
|
50
|
+
"""Perform first login.
|
|
51
|
+
|
|
52
|
+
Performs first login to Toyota's servers. Should be ideally be used
|
|
53
|
+
the very first time you login in. Fetches a token and stores it in
|
|
54
|
+
the controller object for future use.
|
|
55
|
+
|
|
56
|
+
"""
|
|
57
|
+
_LOGGER.debug("Performing first login")
|
|
58
|
+
await self._api.controller.login()
|
|
59
|
+
|
|
60
|
+
async def get_vehicles(self, metric: bool = True) -> Optional[List[Vehicle]]:
|
|
61
|
+
"""Return a list of vehicles."""
|
|
62
|
+
_LOGGER.debug("Getting list of vehicles associated with the account")
|
|
63
|
+
vehicles = await self._api.get_vehicles_endpoint()
|
|
64
|
+
if vehicles.payload is not None:
|
|
65
|
+
return [Vehicle(self._api, v, metric) for v in vehicles.payload]
|
|
66
|
+
|
|
67
|
+
return []
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Toyota Connected Services API constants."""
|
|
2
|
+
|
|
3
|
+
# API URLs
|
|
4
|
+
API_BASE_URL = "HTTPS://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io"
|
|
5
|
+
ACCESS_TOKEN_URL = "HTTPS://b2c-login.toyota-europe.com/oauth2/realms/root/realms/tme/access_token"
|
|
6
|
+
AUTHENTICATE_URL = "HTTPS://b2c-login.toyota-europe.com/json/realms/root/realms/tme/authenticate?authIndexType=service&authIndexValue=oneapp"
|
|
7
|
+
AUTHORIZE_URL = "HTTPS://b2c-login.toyota-europe.com/oauth2/realms/root/realms/tme/authorize?client_id=oneapp&scope=openid+profile+write&response_type=code&redirect_uri=com.toyota.oneapp:/oauth2Callback&code_challenge=plain&code_challenge_method=plain"
|
|
8
|
+
|
|
9
|
+
# Endpoint URLs
|
|
10
|
+
CUSTOMER_ACCOUNT_ENDPOINT = "TBD"
|
|
11
|
+
VEHICLE_ASSOCIATION_ENDPOINT = "/v1/vehicle-association/vehicle"
|
|
12
|
+
VEHICLE_GUID_ENDPOINT = "/v2/vehicle/guid"
|
|
13
|
+
VEHICLE_LOCATION_ENDPOINT = "/v1/location"
|
|
14
|
+
VEHICLE_HEALTH_STATUS_ENDPOINT = "/v1/vehiclehealth/status"
|
|
15
|
+
VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT = "/v1/global/remote/status"
|
|
16
|
+
VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT = "/v1/global/remote/electric/status"
|
|
17
|
+
VEHICLE_TELEMETRY_ENDPOINT = "/v3/telemetry"
|
|
18
|
+
VEHICLE_NOTIFICATION_HISTORY_ENDPOINT = "/v2/notification/history"
|
|
19
|
+
VEHICLE_TRIPS_ENDPOINT = "/v1/trips?from={from_date}&to={to_date}&route={route}&summary={summary}&limit={limit}&offset={offset}" # noqa: E501
|
|
20
|
+
VEHICLE_SERVICE_HISTORY_ENDPONT = "/v1/servicehistory/vehicle/summary"
|