### Run simple_client_example.py Source: https://pytoyoda.github.io/pytoyoda/pytoyoda.html Set up a virtual environment, install the package from the main branch, download the example script, create a credentials file, and run the example. The example script is a playground and not an officially supported interface. ```bash python -m venv pytoyoda source pytoyoda/bin/activate python -m pip install "pytoyoda@git+https://github.com/pytoyoda/pytoyoda@main" curl -LO https://raw.githubusercontent.com/pytoyoda/pytoyoda/main/sandbox/simple_client_example.py # Create a credentials.json file with {"username":"your@mail.tld","password":"yourpassword"} python simple_client_example.py ``` -------------------------------- ### Install pytoyoda with pip Source: https://pytoyoda.github.io/pytoyoda/pytoyoda.html Install the pytoyoda package via pip. ```bash pip install pytoyoda ``` -------------------------------- ### format_odometer example usage Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/utils/formatters.html Example usage of format_odometer, showing input list and expected output dict. Demonstrates flattening and unit suffix behavior. ```python >>> format_odometer( ... [ ... {"type": "distance", "value": 12345, "unit": "km"}, ... {"type": "speed", "value": 60}, ... ] ... ) {'distance': 12345, 'distance_unit': 'km', 'speed': 60} ``` -------------------------------- ### Start time property Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/trips.html Returns the trip start time as a datetime object from the trip summary. Returns None if summary is missing. ```python 84 @computed_field # type: ignore[prop-decorator] 85 @property 86 def start_time(self) -> datetime | None: 87 """Start time. 88 89 Returns: 90 datetime: Start time of trip 91 92 """ 93 return self._trip.summary.start_ts if self._trip.summary else None ``` -------------------------------- ### ClimateStatus.started_at Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/climate.html Returns the timestamp when the current climate run started. ```APIDOC ## ClimateStatus.started_at ### Description When the current climate run started. ### Method property ### Endpoint ClimateStatus.started_at ### Parameters None ### Response #### Success Response - **started_at** (datetime | None) - When the current climate run started. #### Response Example ``` "2024-01-01T00:00:00Z" ``` ``` -------------------------------- ### set_climate method implementation Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Starts or stops remote climate control. A start request includes full settings; a stop is just command="stop". Acknowledgement is response.payload.return_code == "000000". ```python return await self._api.send_climate_control_command(self.vin, request) ``` -------------------------------- ### started_at property Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/climate.html Returns the start time of the current climate run, or None if no status is available. ```python 167 @computed_field # type: ignore[prop-decorator] 168 @property 169 def started_at(self) -> datetime | None: 170 """When the current climate run started.""" 171 return self._status.started_at if self._status else None ``` -------------------------------- ### from_date property Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/summary.html Returns the date the summary started. ```python 160 @computed_field # type: ignore[prop-decorator] 161 @property 162 def from_date(self) -> date: 163 """The date the summary started. 164 165 Returns: 166 date: The date the summary started 167 168 """ 169 return self._from_date ``` -------------------------------- ### get_climate_settings(vin) Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get the current climate control settings. ```APIDOC ## get_climate_settings(vin) ### Description Get the current climate control settings. ### Method GET ### Endpoint VEHICLE_CLIMATE_SETTINGS_ENDPOINT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Returns Model containing climate settings information ``` -------------------------------- ### add_with_none usage examples Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/utils/helpers.html Shows expected outputs for add_with_none with various inputs, including None handling. ```python >>> add_with_none(5, 3) 8 >>> add_with_none(None, 3) 3 >>> add_with_none(5, None) 5 >>> add_with_none(None, None) None ``` -------------------------------- ### get_climate_settings Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get the current climate control settings. ```APIDOC ## get_climate_settings ### Description Get the current climate control settings. ### Method GET ### Endpoint VEHICLE_CLIMATE_SETTINGS_ENDPOINT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Returns Model containing climate settings information ``` -------------------------------- ### Get HTTP Client Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/controller.html Context manager for HTTP client with consistent timeout. ```python @asynccontextmanager async def _get_http_client(self) -> AsyncGenerator: """Context manager for HTTP client with consistent timeout.""" ssl_ctx = await self._get_ssl_context() async with AsyncCacheClient(timeout=self._timeout, verify=ssl_ctx) as client: yield client ``` -------------------------------- ### POST /v2/remote/climate-control Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Start or stop remote climate via POST /v2/remote/climate-control. The unified V2 endpoint replaces the old settings-PUT + control-POST: a `start` request carries the full desired settings (temperature + heating/seat options + `save_settings`); a `stop` is just `command="stop"`. Command success is `response.payload.return_code == "000000"`; confirmation of the actual on/off state is via the climate-status read. ```APIDOC ## POST /v2/remote/climate-control ### Description Start or stop remote climate via POST /v2/remote/climate-control. The unified V2 endpoint replaces the old settings-PUT + control-POST: a `start` request carries the full desired settings (temperature + heating/seat options + `save_settings`); a `stop` is just `command="stop"`. Command success is `response.payload.return_code == "000000"`; confirmation of the actual on/off state is via the climate-status read. ### Method POST ### Endpoint /v2/remote/climate-control ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number #### Request Body - **request** (V2RemoteClimateControlRequestModel) - Required - The V2 climate-control request body. ### Response #### Success Response (200) - **response** (RemoteClimateControlResponseModel) - Model containing the command acknowledgement (request id + return code). #### Response Example ```json { "payload": { "return_code": "000000" } } ``` ``` -------------------------------- ### from_date property Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/summary.html Computed property returning the start date of the summary. ```python @computed_field # type: ignore[prop-decorator] @property def from_date(self) -> date: """The date the summary started. Returns: date: The date the summary started """ return self._from_date ``` -------------------------------- ### Send next charging command Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Sends the next charging start or end time settings to the vehicle. ```python 479 async def send_next_charging_command( 480 self, vin: str, command: NextChargeSettings 481 ) -> ElectricCommandResponseModel: 482 """Send the next charging start/end time to the vehicle. 483 484 Args: 485 vin: Vehicle Identification Number 486 command: NextChargeSettings command to send 487 488 Returns: 489 Model containing status of the command request 490 491 """ 492 return await self._request_and_parse( 493 ElectricCommandResponseModel, 494 "POST", 495 VEHICLE_GLOBAL_REMOTE_ELECTRIC_CONTROL_ENDPOINT, 496 vin=vin, 497 body=command.model_dump(exclude_none=True, by_alias=True), 498 ) ``` -------------------------------- ### ChargeTime Model Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/endpoints/electric.html Defines the hour and minute for charging start or end times. ```python 291class ChargeTime(CustomEndpointBaseModel): 292 """Model representing a charging time configuration. 293 294 Attributes: 295 hour: Hour when charging starts/ends (0-23), e.g., 14 296 minute: Minute when charging starts/ends (0-59), e.g., 30 297 298 """ 299 300 hour: int = Field(alias="hour") 301 minute: int = Field(alias="minute") ``` -------------------------------- ### send_climate_control_command Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Start or stop remote climate via POST /v2/remote/climate-control. The unified V2 endpoint replaces the old settings-PUT + control-POST: a start request carries the full desired settings (temperature + heating/seat options + save_settings); a stop is just command="stop". Command success is response.payload.return_code == "000000"; confirmation of the actual on/off state is via the climate-status read. ```APIDOC ## send_climate_control_command ### Description Start or stop remote climate via POST /v2/remote/climate-control. The unified V2 endpoint replaces the old settings-PUT + control-POST: a start request carries the full desired settings (temperature + heating/seat options + save_settings); a stop is just command="stop". Command success is response.payload.return_code == "000000"; confirmation of the actual on/off state is via the climate-status read. ### Method POST ### Endpoint VEHICLE_CLIMATE_CONTROL_ENDPOINT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number #### Request Body - **request** (V2RemoteClimateControlRequestModel) - Required - The V2 climate-control request body. ### Returns Model containing the command acknowledgement (request id + return code). ``` -------------------------------- ### CustomBaseModel usage example Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/utils/models.html Demonstrates how CustomBaseModel handles type validation, where invalid types may result in None values. ```python >>> class User(CustomBaseModel): ... name: str ... age: int >>> # This won't raise an error, age will be None >>> user = User(name="John", age="not-a-number") >>> print(user.age) None ``` -------------------------------- ### Request JSON with Controller Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/controller.html Example of how to use the request_json method to send an API request and receive a dictionary response. ```python response = await controller.request_json("GET", "/cars", vin="1234567890") ``` -------------------------------- ### send_climate_control_command - Start or stop remote climate via POST /v2/remote/climate-control Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Sends a V2 remote climate control command. The unified endpoint replaces the old settings-PUT + control-POST: a start request carries full desired settings (temperature, heating/seat options, save_settings); a stop is just command="stop". Command success is response.payload.return_code == "000000"; confirmation of the actual on/off state is via the climate-status read. ```python async def send_climate_control_command( self, vin: str, request: V2RemoteClimateControlRequestModel ) -> RemoteClimateControlResponseModel: """Start or stop remote climate via POST /v2/remote/climate-control. The unified V2 endpoint replaces the old settings-PUT + control-POST: a ``start`` request carries the full desired settings (temperature + heating/ seat options + ``save_settings``); a ``stop`` is just ``command="stop"``. Command success is ``response.payload.return_code == "000000"``; confirmation of the actual on/off state is via the climate-status read. Args: vin: Vehicle Identification Number request: The V2 climate-control request body. Returns: Model containing the command acknowledgement (request id + return code). """ return await self._request_and_parse( RemoteClimateControlResponseModel, "POST", VEHICLE_CLIMATE_CONTROL_ENDPOINT, vin=vin, body=request.model_dump(exclude_none=True, by_alias=True), ) ``` -------------------------------- ### Get Vehicle Alias Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the nickname or alias of the vehicle. ```python 306 @computed_field # type: ignore[prop-decorator] 307 @property 308 def alias(self) -> str | None: 309 """Vehicle's alias. 310 311 Returns: 312 Optional[str]: Nickname of vehicle 313 314 """ 315 return self._vehicle_info.nickname ``` -------------------------------- ### Get Vehicle VIN Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the vehicle's VIN number. ```python 295 @computed_field # type: ignore[prop-decorator] 296 @property 297 def vin(self) -> str | None: 298 """Return the vehicles VIN number. 299 300 Returns: 301 Optional[str]: The vehicles VIN number 302 303 """ 304 return self._vehicle_info.vin ``` -------------------------------- ### Get Vehicle Electric Status Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the electric status of the vehicle. ```python 374 @computed_field # type: ignore[prop-decorator] 375 @property 376 def electric_status(self) -> ElectricStatus | None: 377 """Returns the Electric Status of the vehicle. 378 379 Returns: 380 Optional[ElectricStatus]: Electric Status 381 382 """ 383 return ElectricStatus(self._endpoint_data.get("electric_status", None)) ``` -------------------------------- ### Get Vehicle Climate Status Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the vehicle's climate status. ```python 363 @computed_field # type: ignore[prop-decorator] 364 @property 365 def climate_status(self) -> ClimateStatus | None: 366 """Return the vehicle climate status. 367 368 Returns: 369 Optional[ClimateStatus]: A climate status 370 371 """ 372 return ClimateStatus(self._endpoint_data.get("climate_status", None)) ``` -------------------------------- ### Get vehicle notifications Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Retrieves a list of notifications for the vehicle, or None if not supported. ```python 430 @computed_field # type: ignore[prop-decorator] 431 @property 432 def notifications(self) -> list[Notification] | None: 433 r"""Returns a list of notifications for the vehicle. 434 435 Returns: 436 Optional[list[Notification]]: A list of notifications for the vehicle, 437 or None if not supported. 438 439 """ 440 if "notifications" in self._endpoint_data: 441 ret: list[Notification] = [] 442 for p in self._endpoint_data["notifications"].payload: 443 ret.extend(Notification(n) for n in p.notifications) 444 return ret 445 446 return None ``` -------------------------------- ### Get Vehicle Dashboard Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the vehicle dashboard containing information like fuel levels. ```python 332 @computed_field # type: ignore[prop-decorator] 333 @property 334 def dashboard(self) -> Dashboard | None: 335 """Returns the Vehicle dashboard. 336 337 The dashboard consists of items of information you would expect to 338 find on the dashboard. i.e. Fuel Levels. 339 340 Returns: 341 Optional[Dashboard]: A dashboard 342 343 """ 344 # Always returns a Dashboard object as we can always get the odometer value 345 return Dashboard( 346 self._endpoint_data.get("telemetry", None), 347 self._endpoint_data.get("electric_status", None), 348 self._endpoint_data.get("health_status", None), 349 self._metric, 350 ) ``` -------------------------------- ### Set remote climate control Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Starts or stops remote climate control. Acknowledgement is confirmed via return_code '000000'. ```python async def set_climate( self, request: V2RemoteClimateControlRequestModel ) -> RemoteClimateControlResponseModel: """Start or stop remote climate control (POST /v2/remote/climate-control). A ``start`` request carries the full desired settings (temperature + heating/seat options + ``save_settings``); a ``stop`` is just ``command="stop"``. Acknowledgement is ``response.payload.return_code == "000000"``; confirm the actual on/off state via the climate-status read. Args: request: The V2 climate-control request body. Returns: RemoteClimateControlResponseModel: The command acknowledgement. """ return await self._api.send_climate_control_command(self.vin, request) ``` -------------------------------- ### Get Vehicle Type Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the type of vehicle as a string (fuel, mildhybrid, phev, or ev). ```python 317 @computed_field # type: ignore[prop-decorator] 318 @property 319 def type(self) -> str | None: 320 """Returns the "type" of vehicle. 321 322 Returns: 323 Optional[str]: "fuel" if only fuel based 324 "mildhybrid" if hybrid 325 "phev" if plugin hybrid 326 "ev" if full electric vehicle 327 328 """ 329 vehicle_type = VehicleType.from_vehicle_info(self._vehicle_info) 330 return vehicle_type.name.lower() ``` -------------------------------- ### MyT.__init__ Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Initializes the Toyota Connected Services client with the provided credentials and configuration. ```APIDOC ## MyT.__init__ ### Description Initializes the Toyota Connected Services client with the provided credentials and configuration. ### Method Constructor ### Signature `MyT(username: str, password: str, use_metric: bool = True, brand: str = 'T', controller_class: type[pytoyoda.controller.Controller] = )` ### Parameters - **username** (str) - Required - Email address for Toyota account login - **password** (str) - Required - Password for Toyota account - **use_metric** (bool) - Optional - Whether to use metric units (True) or imperial units (False) - **brand** (str) - Optional - Brand of the car (T for Toyota, L for Lexus) - **controller_class** (type[Controller]) - Optional - Controller class to use for API communication ### Raises - **ToyotaInvalidUsernameError** - If username is invalid or missing @ symbol ``` -------------------------------- ### GET /v2/remote/trips Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get a list of trips for a vehicle within a date range. ```APIDOC ## GET /v2/remote/trips ### Description Get a list of trips for a vehicle within a date range. ### Method GET ### Endpoint /v2/remote/trips ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number #### Query Parameters - **from_date** (date) - Required - Start date for trip data (inclusive, cannot be in future) - **to_date** (date) - Required - End date for trip data (inclusive, cannot be in future) - **route** (boolean) - Optional - If True, returns route coordinates for each trip - **summary** (boolean) - Optional - If True, returns monthly and daily trip summaries - **limit** (integer) - Optional - Maximum number of trips to return (max 50) - **offset** (integer) - Optional - Starting offset for pagination ### Response #### Success Response (200) - **response** (TripsResponseModel) - Model containing trip information #### Response Example ```json { "trips": [] } ``` ``` -------------------------------- ### MyT.__init__ Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Initializes the Toyota Connected Services client with user credentials and configuration options. Validates the username format and sets up the API controller. ```APIDOC ## MyT.__init__ ### Description Initializes the Toyota Connected Services client with user credentials and configuration options. Validates the username format and sets up the API controller. ### Method Constructor ### Signature ```python MyT(username: str, password: str, use_metric: bool = True, brand: str = "T", controller_class: type[Controller] = Controller) -> None ``` ### Parameters - **username** (str) - Required - Email address for Toyota account login - **password** (str) - Required - Password for Toyota account - **use_metric** (bool) - Optional - Whether to use metric units (True) or imperial units (False). Default: True - **brand** (str) - Optional - Brand of the car (T for Toyota, L for Lexus). Default: "T" - **controller_class** (type[Controller]) - Optional - Controller class to use for API communication. Default: Controller ### Raises - **ToyotaInvalidUsernameError** - If username is invalid or missing @ symbol ### Example ```python client = MyT(username="user@example.com", password="password", use_metric=True) ``` ``` -------------------------------- ### GET /api/vehicles/{vin}/trips Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get a list of trips for a vehicle within a date range. ```APIDOC ## GET /api/vehicles/{vin}/trips ### Description Get a list of trips for a vehicle within a date range. ### Method GET ### Endpoint /api/vehicles/{vin}/trips ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number #### Query Parameters - **from_date** (string) - Required - Start date for trip data (inclusive, cannot be in future) - **to_date** (string) - Required - End date for trip data (inclusive, cannot be in future) - **route** (boolean) - Optional - If True, returns route coordinates for each trip - **summary** (boolean) - Optional - If True, returns monthly and daily trip summaries - **limit** (integer) - Optional - Maximum number of trips to return (max 50) - **offset** (integer) - Optional - Starting offset for pagination ### Response #### Success Response (200) - **TripsResponseModel** - Model containing trip information ``` -------------------------------- ### Get vehicle location Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Returns the latest reported location of the vehicle. Returns None if the vehicle does not support location services. ```python 416 @computed_field # type: ignore[prop-decorator] 417 @property 418 def location(self) -> Location | None: 419 """Return the vehicles latest reported Location. 420 421 Returns: 422 Optional[Location]: The latest location or None. If None vehicle car 423 does not support providing location information. 424 _Note_ an empty location object can be returned when the Vehicle 425 supports location but none is currently available. 426 427 """ 428 return Location(self._endpoint_data.get("location", None)) ``` -------------------------------- ### Get SSL Context Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/controller.html Retrieves a cached SSL context, building it off the event loop on first use to avoid blocking the loop during synchronous CA bundle reading. ```python async def _get_ssl_context(self) -> ssl.SSLContext: """Return a cached SSL context, building it off the event loop on first use. httpx.create_ssl_context() reads the CA bundle synchronously, which blocks the event loop for ~1-10ms and trips Home Assistant's blocking-call watchdog. By caching the context on the Controller and sharing it across AsyncClient constructions, we pay that cost once per Controller lifetime instead of per HTTP client. """ if self._ssl_ctx is None: loop = asyncio.get_running_loop() self._ssl_ctx = await loop.run_in_executor(None, httpx.create_ssl_context) return self._ssl_ctx ``` -------------------------------- ### Initialize Controller class Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/controller.html The constructor sets up authentication credentials, API URLs, and initializes the token cache and HTTP client state. ```python 59 def __init__( 60 self, username: str, password: str, brand: str = "T", timeout: int = 60 61 ) -> None: 62 """Initialize Controller class. 63 64 Args: 65 username: Toyota account username 66 password: Toyota account password 67 brand: Brand of the car (T for Toyota, L for Lexus) 68 timeout: HTTP request timeout in seconds 69 70 """ 71 self._username: str = username 72 self._password: str = password 73 self._brand: str = brand 74 self._timeout = timeout 75 76 # URLs 77 self._api_base_url = httpx.URL(API_BASE_URL) 78 self._access_token_url = httpx.URL(ACCESS_TOKEN_URL) 79 self._authenticate_url = httpx.URL(AUTHENTICATE_URL) 80 self._authorize_url = httpx.URL(AUTHORIZE_URL) 81 82 # Authentication state 83 self._token_info: TokenInfo | None = None 84 85 # Reused httpx.AsyncClient for data requests. Lazily constructed inside 86 # an async context and kept for the lifetime of the Controller, so that 87 # SSL context + TCP connection pool survive across request_raw calls. 88 self._client: httpx.AsyncClient | None = None 89 90 # Cached SSL context shared by every AsyncClient this Controller builds. 91 # ssl.create_default_context() reads the CA bundle from disk 92 # synchronously, which trips Home Assistant's blocking-call watchdog 93 # when called from the event loop (one warning per AsyncClient 94 # construction). We build it once in an executor and reuse. 95 self._ssl_ctx: ssl.SSLContext | None = None 96 97 # Load from cache if available 98 if self._username in self._TOKEN_CACHE: 99 self._token_info = self._TOKEN_CACHE[self._username] ``` -------------------------------- ### GET /v1/vehicle/status Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get the latest telemetry data for a vehicle. Includes current fuel level, distance to empty, and odometer. ```APIDOC ## GET /v1/vehicle/status ### Description Get the latest telemetry data for a vehicle. Includes current fuel level, distance to empty, and odometer. ### Method GET ### Endpoint /v1/vehicle/status ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Request Example No request body is required. ### Response #### Success Response (200) - **fuel_level** (number) - Current fuel level - **distance_to_empty** (number) - Distance to empty - **odometer** (number) - Odometer reading #### Response Example { "fuel_level": 50.0, "distance_to_empty": 300, "odometer": 12345 } ``` -------------------------------- ### Initialize MyT client and retrieve vehicle data Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Initializes the MyT client with credentials and metric preference, logs in, and iterates through vehicles to update and print their dashboard information. ```python client = MyT(username="user@example.com", password="password", use_metric=True) await client.login() vehicles = await client.get_vehicles() for vehicle in vehicles: await vehicle.update() print(f"Dashboard: {vehicle.dashboard}") ``` -------------------------------- ### ChargingSchedule class definition with validation and scheduling methods Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/endpoints/electric.html Defines the ChargingSchedule model with fields for id, enabled, type, start_time, end_time, and days. Includes a field validator ensuring at least one day is enabled, and methods to compute the next start datetime and the end datetime/duration for a scheduled charge window. ```python class ChargingSchedule(CustomEndpointBaseModel): """Model representing a charging schedule returned by the API. Attributes: id: Schedule identifier enabled: Whether the schedule is enabled type: Type of schedule (startEnd, startOnly) start_time: Mandatory start time object end_time: Optional end time object days: Days object with enabled weekdays """ id: int = Field(alias="id") enabled: bool = Field(alias="enabled") type: str = Field(alias="type") start_time: "ChargeTime" = Field(alias="startTime") end_time: Optional["ChargeTime"] = Field(alias="endTime", default=None) days: Days = Field(alias="days") @field_validator("days", mode="after") @classmethod def _validate_days(cls, v: Days) -> Days: if v is None: error_message = ( "`days` must be present and contain at least one enabled day" ) raise ValueError(error_message) if not any( bool(getattr(v, d, None)) for d in ("mon", "tue", "wed", "thu", "fri", "sat", "sun") ): error_message = "At least one day must be enabled in `days`" raise ValueError(error_message) return v def _next_start(self, ref: datetime) -> datetime | None: """Compute the next start datetime for this schedule after `ref`. Returns the earliest candidate datetime or None if no weekdays enabled. """ names = ("mon", "tue", "wed", "thu", "fri", "sat", "sun") enabled_wd = [i for i, n in enumerate(names) if bool(getattr(self.days, n, 0))] if not enabled_wd: return None tz = ref.tzinfo def _candidate_for_weekday(wd: int) -> datetime: days_ahead = (wd - ref.weekday() + 7) % 7 candidate_date = ref.date() + timedelta(days=days_ahead) candidate_dt = datetime.combine( candidate_date, time(self.start_time.hour, self.start_time.minute), tzinfo=tz, ) if candidate_dt <= ref: candidate_dt += timedelta(days=7) return candidate_dt candidates = [_candidate_for_weekday(wd) for wd in enabled_wd] return min(candidates) if candidates else None def _end_and_duration( self, start_dt: datetime ) -> tuple[datetime | None, timedelta | None]: """Compute end datetime and duration given a start datetime. Returns (end_dt, duration) where either may be None. """ if self.end_time is None: return None, None end_dt = datetime.combine( start_dt.date(), time(self.end_time.hour, self.end_time.minute), tzinfo=start_dt.tzinfo, ) if end_dt <= start_dt: end_dt += timedelta(days=1) return end_dt, end_dt - start_dt def next_occurrence( self, ref: datetime | None = None ) -> Optional["ScheduledChargeWindow"]: """Return the next scheduled charge window for this schedule after `ref`. Returns a `ScheduledChargeWindow` containing start, optional end and duration. """ if not self.enabled: return None ref = ref or datetime.now(timezone.utc).astimezone() start_dt = self._next_start(ref) if start_dt is None: return None end_dt, duration = self._end_and_duration(start_dt) return ScheduledChargeWindow(start=start_dt, end=end_dt, duration=duration) ``` -------------------------------- ### pytoyoda package __init__.py Source: https://pytoyoda.github.io/pytoyoda/pytoyoda.html The package's __init__.py file, which imports the MyT client and sets the package version using importlib_metadata. ```python """Toyota Connected Services Client. .. include:: ../README.md """ from importlib_metadata import version from pytoyoda.client import MyT # noqa : F401 __version__ = version(__name__) ``` -------------------------------- ### MyT.login - Perform initial login Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Performs the initial login to Toyota Connected Services. Must be called before any API requests to ensure authentication. Raises ToyotaLoginError if login fails. ```python 78 async def login(self) -> None: 79 """Perform initial login to Toyota Connected Services. 80 This should be called before making any API requests to ensure proper authentication. It will fetch and store access tokens for subsequent requests. Raises: ToyotaLoginError: If login fails for any reason """ 89 logger.debug("Performing initial login") 90 try: 91 await self._api.controller.login() 92 logger.debug("Login successful") 93 except ToyotaLoginError as error: 94 logger.error("Login failed: '{}'.", str(error)) 95 raise ``` -------------------------------- ### get_remote_status Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get general information about a vehicle. ```APIDOC ## get_remote_status ### Description Get general information about a vehicle. ### Method GET ### Endpoint VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Response #### Success Response - **RemoteStatusResponseModel** - Model containing general vehicle status #### Response Example ```json { "status": "string" } ``` ``` -------------------------------- ### login method Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/controller.html Performs the initial login to the Toyota API if the current token is invalid. ```python 127 async def login(self) -> None: 128 """Perform initial login if necessary.""" 129 if not self._is_token_valid(): 130 await self._update_token() ``` -------------------------------- ### MyT.__init__ - Initialize Toyota Connected Services client Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Initializes the MyT client. Validates that the username is a non-empty string containing an '@' symbol, raising ToyotaInvalidUsernameError otherwise. Stores the API controller and metric/imperial unit preference. ```python 42 def __init__( 43 self, 44 username: str, 45 password: str, 46 use_metric: bool = True, # noqa : FBT001, FBT002 47 brand: str = "T", 48 controller_class: type[Controller] = Controller, 49 ) -> None: 50 """Initialize the Toyota Connected Services client. 51 52 Args: 53 username: Email address for Toyota account login 54 password: Password for Toyota account 55 use_metric: Whether to use metric units (True) or imperial units (False) 56 brand: Brand of the car (T for Toyota, L for Lexus) 57 controller_class: Controller class to use for API communication 58 Raises: ToyotaInvalidUsernameError: If username is invalid or missing @ symbol 59 """ 60 if not username or "@" not in username: 61 msg = "Invalid username format. Must be a valid email address." 62 raise ToyotaInvalidUsernameError(msg) 63 64 self._api = Api( 65 controller_class( 66 username=username, 67 password=password, 68 brand=brand, 69 ), 70 ) 71 self._use_metric = use_metric 72 73 logger.debug("MyT client initialized for user: '{}'.", username) ``` -------------------------------- ### Initialize API controller Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Initializes the API instance with a controller to manage communication. ```python 79 def __init__(self, controller: Controller) -> None: 80 """Initialize the API with a controller for communication. 81 82 Args: 83 controller: A controller instance to manage the API communication 84 85 """ 86 self.controller = controller ``` -------------------------------- ### Get General Vehicle Status Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Retrieves general information about a vehicle. ```python return await self._request_and_parse( RemoteStatusResponseModel, "GET", VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT, vin=vin, ) ``` -------------------------------- ### Summary class initialization Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/summary.html Base class for Daily, Weekly, Monthly, and Yearly summaries. Initializes with summary data, metric flag, date range, and optional hybrid data. ```python class Summary(CustomAPIBaseModel[type[T]]): """Base class of Daily, Weekly, Monthly, Yearly summary.""" def __init__( self, summary: _SummaryBaseModel, metric: bool, # noqa : FBT001 from_date: date, to_date: date, hdc: _HDCModel | None = None, **kwargs: dict, ) -> None: """Initialise Class. Args: summary (_SummaryBaseModel, required): Contains all the summary information metric (bool, required): Report in Metric or Imperial from_date (date, required): Start date for this summary to_date (date, required): End date for this summary hdc: (_HDCModel, optional): Hybrid data if available **kwargs: Additional keyword arguments passed to the parent class """ data = { "summary": summary, "metric": metric, "from_date": from_date, "to_date": to_date, "hdc": hdc, } super().__init__(data=data, **kwargs) # type: ignore[reportArgumentType, arg-type] self._summary: _SummaryBaseModel = summary self._metric: bool = metric self._from_date: date = from_date self._to_date: date = to_date self._hdc: _HDCModel | None = hdc self._distance_unit: str = KILOMETERS_UNIT if metric else MILES_UNIT ``` -------------------------------- ### Get Registered Vehicles Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Retrieves a list of all vehicles registered with the Toyota account. ```python return await self._request_and_parse( VehiclesResponseModel, "GET", VEHICLE_GUID_ENDPOINT ) ``` -------------------------------- ### HeatingOptions model with front_defroster, rear_defogger, steering_heater Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/climate.html Defines the HeatingOptions model with computed properties for front_defroster, rear_defogger, and steering_heater, each returning a tristate bool via _tristate. The constructor accepts a HeatingOptionsModel and passes it to the parent class. ```python 52class HeatingOptions(CustomAPIBaseModel[HeatingOptionsModel]): 53 """Defroster / defogger / steering-heater states.""" 54 55 def __init__(self, options: HeatingOptionsModel, **kwargs: dict) -> None: 56 """Initialize heating options. 57 58 Args: 59 options (HeatingOptionsModel): The heating option states. 60 **kwargs: Additional keyword arguments passed to the parent class. 61 62 """ 63 super().__init__(data=options, **kwargs) 64 65 @computed_field # type: ignore[prop-decorator] 66 @property 67 def front_defroster(self) -> bool | None: 68 """Whether the front defroster is on.""" 69 return _tristate( 70 self._data.front_defroster, _TOGGLE_ON_STATES, _TOGGLE_OFF_STATES 71 ) 72 73 @computed_field # type: ignore[prop-decorator] 74 @property 75 def rear_defogger(self) -> bool | None: 76 """Whether the rear defogger is on.""" 77 return _tristate( 78 self._data.rear_defogger, _TOGGLE_ON_STATES, _TOGGLE_OFF_STATES 79 ) 80 81 @computed_field # type: ignore[prop-decorator] 82 @property 83 def steering_heater(self) -> bool | None: """Whether the steering-wheel heater is on.""" 84 return _tristate( 85 self._data.steering_heater, _TOGGLE_ON_STATES, _TOGGLE_OFF_STATES 86 ) ``` -------------------------------- ### TripLocations Model Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/trips.html Pydantic model representing start and end trip locations. ```python class TripLocations(BaseModel): """Trip locations.""" start: TripPositions | None end: TripPositions | None ``` -------------------------------- ### RefreshStatus Module Implementation Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/endpoints/refresh_status.html The full implementation of the RefreshStatus models, including imports and class definitions. ```python 1"""Toyota Connected Services API - POST /v1/remote/status. 2 3Sent before reading /v1/vehicle/status to wake the vehicle's cellular modem so 4the gateway populates the cache that GET reads. The old 5/v1/global/remote/refresh-status route required a deviceId/deviceType/guid/vin 6body and is now SigV4-fenced (APIGW-403); the migrated /v1/remote/* route takes 7the vin as a header only (no body). Contract confirmed against a live car 82026-07-01: 9 10 POST /v1/remote/status (vin header, no body) 11 -> 200 OK 12 payload.returnCode == "000000" -> wake accepted 13 payload.returnCode != "000000" -> vehicle does not support endpoint 14 (returnCode also surfaces partial-failures for transient backend issues 15 but those are rare; treating non-000000 as "not supported" is safe.) 16""" 17 18from __future__ import annotations 19 20from pydantic import Field 21 22from pytoyoda.models.endpoints.common import StatusModel 23from pytoyoda.utils.models import CustomEndpointBaseModel 24 25 26class RefreshStatusPayloadModel(CustomEndpointBaseModel): 27 """Payload of the POST /v1/remote/status response.""" 28 29 app_request_no: str | None = Field(alias="appRequestNo", default=None) 30 return_code: str | None = Field(alias="returnCode", default=None) 31 32 33class RefreshStatusResponseModel(StatusModel): 34 """Full response wrapper for POST /v1/remote/status.""" 35 36 payload: RefreshStatusPayloadModel | None = None ``` -------------------------------- ### MyT.login Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Performs initial login to Toyota Connected Services. This should be called before making any API requests to ensure proper authentication. ```APIDOC ## MyT.login ### Description Performs initial login to Toyota Connected Services. This should be called before making any API requests to ensure proper authentication. It will fetch and store access tokens for subsequent requests. ### Method async ### Signature ```python async def login(self) -> None ``` ### Parameters None ### Raises - **ToyotaLoginError** - If login fails for any reason ### Example ```python await client.login() ``` ``` -------------------------------- ### send_next_charging_command method implementation Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/vehicle.html Sends a next charging command to the vehicle. ```python return await self._api.send_next_charging_command(self.vin, command=command) ``` -------------------------------- ### MyT.login Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/client.html Performs initial login to Toyota Connected Services. This should be called before making any API requests to ensure proper authentication. It will fetch and store access tokens for subsequent requests. ```APIDOC ## MyT.login ### Description Performs initial login to Toyota Connected Services. This should be called before making any API requests to ensure proper authentication. It will fetch and store access tokens for subsequent requests. ### Method async ### Signature `async def login(self) -> None` ### Parameters None ### Raises - **ToyotaLoginError** - If login fails for any reason ``` -------------------------------- ### get_remote_status API method Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Gets general information about a vehicle using the provided VIN. ```python 195 async def get_remote_status(self, vin: str) -> RemoteStatusResponseModel: 196 """Get general information about a vehicle. 197 198 Args: 199 vin: Vehicle Identification Number 200 201 Returns: 202 Model containing general vehicle status 203 204 """ 205 return await self._request_and_parse( 206 RemoteStatusResponseModel, 207 "GET", 208 VEHICLE_GLOBAL_REMOTE_STATUS_ENDPOINT, 209 vin=vin, 210 ) ``` -------------------------------- ### Service History Models Implementation Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/models/endpoints/service_history.html The complete implementation of the service history models, including ServiceHistoryModel, ServiceHistoriesModel, and ServiceHistoryResponseModel. ```python 1"""Toyota Connected Services API - Service History Models.""" 2 3from datetime import date 4from typing import Any 5 6from pydantic import Field 7 8from pytoyoda.models.endpoints.common import StatusModel 9from pytoyoda.utils.models import CustomEndpointBaseModel 10 11 12class ServiceHistoryModel(CustomEndpointBaseModel): 13 """Represents a service history record. 14 15 Attributes: 16 customer_created_record (bool): Indicates if the record was created by 17 the customer. 18 mileage (Optional[int]): The mileage at the time of the service. 19 notes (Any): Additional notes about the service. 20 operations_performed (Any): The operations performed during the service. 21 ro_number (Any): The RO (Repair Order) number associated with the service. 22 service_category (str): The category of the service. 23 service_date (date): The date of the service. 24 service_history_id (str): The ID of the service history record. 25 service_provider (str): The service provider. 26 servicing_dealer (Any): The dealer that performed the service. 27 unit (Optional[str]): The unit associated with the service mileage. 28 29 """ 30 31 customer_created_record: bool | None = Field(alias="customerCreatedRecord") 32 mileage: int | None = None 33 notes: Any 34 operations_performed: Any = Field(alias="operationsPerformed") 35 ro_number: Any = Field(alias="roNumber") 36 service_category: str | None = Field(alias="serviceCategory") 37 service_date: date | None = Field(alias="serviceDate") 38 service_history_id: str | None = Field(alias="serviceHistoryId") 39 service_provider: str | None = Field(alias="serviceProvider") 40 servicing_dealer: Any = Field(alias="servicingDealer", default=None) 41 unit: str | None = None 42 43 44class ServiceHistoriesModel(CustomEndpointBaseModel): 45 r"""Model representing a list of service histories. 46 47 Attributes: 48 service_histories (list[Optional[ServiceHistoryModel]]): A list of all 49 service histories. Defaults to []. 50 51 """ 52 53 service_histories: list[ServiceHistoryModel | None] | None = Field( 54 alias="serviceHistories", default=[] 55 ) 56 57 58class ServiceHistoryResponseModel(StatusModel): 59 """Model representing a service history response. 60 61 Inherits from StatusModel. 62 63 Attributes: 64 payload (Optional[ServiceHistoriesModel]): The service history payload. 65 Defaults to None. 66 67 """ 68 69 payload: ServiceHistoriesModel | None = None ``` -------------------------------- ### get_service_history Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get the service history for a vehicle, including service category, date, and dealer information. ```APIDOC ## get_service_history ### Description Get the service history for a vehicle, including service category, date, and dealer information. ### Method GET ### Endpoint VEHICLE_SERVICE_HISTORY_ENDPONT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Returns Model containing service history information ``` -------------------------------- ### get_service_history(vin) Source: https://pytoyoda.github.io/pytoyoda/pytoyoda/api.html Get the service history for a vehicle. Includes service category, date, and dealer information. ```APIDOC ## get_service_history(vin) ### Description Get the service history for a vehicle. Includes service category, date, and dealer information. ### Method GET ### Endpoint VEHICLE_SERVICE_HISTORY_ENDPONT ### Parameters #### Path Parameters - **vin** (string) - Required - Vehicle Identification Number ### Returns Model containing service history information ```