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.
Files changed (38) hide show
  1. pytoyoda-2.3.1/LICENSE +21 -0
  2. pytoyoda-2.3.1/PKG-INFO +98 -0
  3. pytoyoda-2.3.1/README.md +67 -0
  4. pytoyoda-2.3.1/pyproject.toml +92 -0
  5. pytoyoda-2.3.1/pytoyoda/__init__.py +6 -0
  6. pytoyoda-2.3.1/pytoyoda/api.py +272 -0
  7. pytoyoda-2.3.1/pytoyoda/client.py +67 -0
  8. pytoyoda-2.3.1/pytoyoda/const.py +20 -0
  9. pytoyoda-2.3.1/pytoyoda/controller.py +304 -0
  10. pytoyoda-2.3.1/pytoyoda/exceptions.py +25 -0
  11. pytoyoda-2.3.1/pytoyoda/models/dashboard.py +221 -0
  12. pytoyoda-2.3.1/pytoyoda/models/electric_status.py +120 -0
  13. pytoyoda-2.3.1/pytoyoda/models/endpoints/account.py +81 -0
  14. pytoyoda-2.3.1/pytoyoda/models/endpoints/common.py +51 -0
  15. pytoyoda-2.3.1/pytoyoda/models/endpoints/electric.py +57 -0
  16. pytoyoda-2.3.1/pytoyoda/models/endpoints/location.py +50 -0
  17. pytoyoda-2.3.1/pytoyoda/models/endpoints/notifications.py +70 -0
  18. pytoyoda-2.3.1/pytoyoda/models/endpoints/service_history.py +70 -0
  19. pytoyoda-2.3.1/pytoyoda/models/endpoints/status.py +89 -0
  20. pytoyoda-2.3.1/pytoyoda/models/endpoints/telemetry.py +43 -0
  21. pytoyoda-2.3.1/pytoyoda/models/endpoints/trips.py +215 -0
  22. pytoyoda-2.3.1/pytoyoda/models/endpoints/vehicle_guid.py +467 -0
  23. pytoyoda-2.3.1/pytoyoda/models/endpoints/vehicle_health.py +44 -0
  24. pytoyoda-2.3.1/pytoyoda/models/location.py +69 -0
  25. pytoyoda-2.3.1/pytoyoda/models/lock_status.py +273 -0
  26. pytoyoda-2.3.1/pytoyoda/models/nofication.py +82 -0
  27. pytoyoda-2.3.1/pytoyoda/models/service_history.py +140 -0
  28. pytoyoda-2.3.1/pytoyoda/models/summary.py +193 -0
  29. pytoyoda-2.3.1/pytoyoda/models/trips.py +196 -0
  30. pytoyoda-2.3.1/pytoyoda/models/vehicle.py +566 -0
  31. pytoyoda-2.3.1/pytoyoda/py.typed +0 -0
  32. pytoyoda-2.3.1/pytoyoda/utils/__init__.py +1 -0
  33. pytoyoda-2.3.1/pytoyoda/utils/conversions.py +37 -0
  34. pytoyoda-2.3.1/pytoyoda/utils/formatters.py +12 -0
  35. pytoyoda-2.3.1/pytoyoda/utils/helpers.py +14 -0
  36. pytoyoda-2.3.1/pytoyoda/utils/locale.py +15 -0
  37. pytoyoda-2.3.1/pytoyoda/utils/log_utils.py +152 -0
  38. 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.
@@ -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
+ ![GitHub Workflow](https://img.shields.io/github/actions/workflow/status/pytoyoda/pytoyoda/build.yml)
32
+ ![Codecov](https://img.shields.io/codecov/c/github/pytoyoda/pytoyoda)
33
+ ![Commit activity](https://img.shields.io/github/commit-activity/y/pytoyoda/pytoyoda)
34
+ ![GitHub Release](https://img.shields.io/github/release/pytoyoda/pytoyoda.svg)
35
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/pytoyoda)
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
+
@@ -0,0 +1,67 @@
1
+ ![GitHub Workflow](https://img.shields.io/github/actions/workflow/status/pytoyoda/pytoyoda/build.yml)
2
+ ![Codecov](https://img.shields.io/codecov/c/github/pytoyoda/pytoyoda)
3
+ ![Commit activity](https://img.shields.io/github/commit-activity/y/pytoyoda/pytoyoda)
4
+ ![GitHub Release](https://img.shields.io/github/release/pytoyoda/pytoyoda.svg)
5
+ ![PyPI - Downloads](https://img.shields.io/pypi/dm/pytoyoda)
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,6 @@
1
+ """Toyota Connected Services Client."""
2
+ from importlib_metadata import version
3
+
4
+ from pytoyoda.client import MyT # noqa
5
+
6
+ __version__ = version(__name__)
@@ -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"