Skip to content

Commit

Permalink
revert workflow changes
Browse files Browse the repository at this point in the history
  • Loading branch information
CM000n committed Dec 20, 2023
1 parent 69e21a3 commit 9164494
Show file tree
Hide file tree
Showing 32 changed files with 696 additions and 251 deletions.
56 changes: 40 additions & 16 deletions mytoyota/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ def __init__(self, controller: Controller) -> None: # noqa: D417

async def _request_and_parse(self, model, method: str, endpoint: str, **kwargs):
"""Parse requests and responses."""
response = await self.controller.request_json(method=method, endpoint=endpoint, **kwargs)
response = await self.controller.request_json(
method=method, endpoint=endpoint, **kwargs
)
return model(**response)

async def set_vehicle_alias_endpoint(self, alias: str, guid: str, vin: str):
Expand All @@ -58,7 +60,7 @@ async def set_vehicle_alias_endpoint(self, alias: str, guid: str, vin: str):
body={"guid": guid, "vin": vin, "nickName": alias},
)

# TODO: Remove for now as it seems to have no effect. The App is sending it!
# TODO: Remove for now as it seems to have no effect. The App is sending it! # pylint: disable=W0511
# async def post_wake_endpoint(self) -> None:
# """Send a wake request to the vehicle."""
# await self.controller.request_raw(
Expand All @@ -67,9 +69,13 @@ async def set_vehicle_alias_endpoint(self, alias: str, guid: str, vin: str):

async def get_vehicles_endpoint(self) -> VehiclesResponseModel:
"""Return list of vehicles registered with provider."""
return await self._request_and_parse(VehiclesResponseModel, "GET", VEHICLE_GUID_ENDPOINT)
return await self._request_and_parse(

Check warning on line 72 in mytoyota/api.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/api.py#L72

Added line #L72 was not covered by tests
VehiclesResponseModel, "GET", VEHICLE_GUID_ENDPOINT
)

async def get_location_endpoint(self, vin: str) -> LocationResponseModel: # noqa: D417
async def get_location_endpoint(
self, vin: str
) -> LocationResponseModel: # noqa: D417
"""Get the last known location of your car. Only updates when car is parked.
Response includes Lat, Lon position. * If supported.
Expand All @@ -78,18 +84,25 @@ async def get_location_endpoint(self, vin: str) -> LocationResponseModel: # noq
----------
vin: str: The vehicles VIN
"""
return await self._request_and_parse(LocationResponseModel, "GET", VEHICLE_LOCATION_ENDPOINT, vin=vin)
return await self._request_and_parse(

Check warning on line 87 in mytoyota/api.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/api.py#L87

Added line #L87 was not covered by tests
LocationResponseModel, "GET", VEHICLE_LOCATION_ENDPOINT, vin=vin
)

async def get_vehicle_health_status_endpoint(self, vin: str) -> VehicleHealthResponseModel: # noqa: D417
async def get_vehicle_health_status_endpoint(
self, vin: str
) -> VehicleHealthResponseModel: # noqa: D417
"""Get the latest health status.
Response includes the quantity of engine oil and any dashboard warning lights. * If supported.
Response includes the quantity of engine oil and any dashboard warning lights. \n
* If supported.
Parameters
----------
vin: str: The vehicles VIN
"""
return await self._request_and_parse(VehicleHealthResponseModel, "GET", VEHICLE_HEALTH_STATUS_ENDPOINT, vin=vin)
return await self._request_and_parse(

Check warning on line 103 in mytoyota/api.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/api.py#L103

Added line #L103 was not covered by tests
VehicleHealthResponseModel, "GET", VEHICLE_HEALTH_STATUS_ENDPOINT, vin=vin
)

async def get_remote_status_endpoint(self, vin: str) -> RemoteStatusResponseModel:
"""Get information about the vehicle."""
Expand All @@ -100,11 +113,13 @@ async def get_remote_status_endpoint(self, vin: str) -> RemoteStatusResponseMode
vin=vin,
)

async def get_vehicle_electric_status_endpoint(self, vin: str) -> ElectricResponseModel: # noqa: D417
async def get_vehicle_electric_status_endpoint(
self, vin: str
) -> ElectricResponseModel: # noqa: D417
"""Get the latest electric status.
Response includes current battery level, EV Range, EV Range with AC, fuel level, fuel range and
current charging status
Response includes current battery level, EV Range, EV Range with AC, \n
fuel level, fuel range and current charging status
Parameters
----------
Expand All @@ -117,7 +132,9 @@ async def get_vehicle_electric_status_endpoint(self, vin: str) -> ElectricRespon
vin=vin,
)

async def get_telemetry_endpoint(self, vin: str) -> TelemetryResponseModel: # noqa: D417
async def get_telemetry_endpoint(
self, vin: str
) -> TelemetryResponseModel: # noqa: D417
"""Get the latest telemetry status.
Response includes current fuel level, distance to empty and odometer
Expand All @@ -126,9 +143,13 @@ async def get_telemetry_endpoint(self, vin: str) -> TelemetryResponseModel: # n
----------
vin: str: The vehicles VIN
"""
return await self._request_and_parse(TelemetryResponseModel, "GET", VEHICLE_TELEMETRY_ENDPOINT, vin=vin)
return await self._request_and_parse(

Check warning on line 146 in mytoyota/api.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/api.py#L146

Added line #L146 was not covered by tests
TelemetryResponseModel, "GET", VEHICLE_TELEMETRY_ENDPOINT, vin=vin
)

async def get_notification_endpoint(self, vin: str) -> NotificationResponseModel: # noqa: D417
async def get_notification_endpoint(
self, vin: str
) -> NotificationResponseModel: # noqa: D417
"""Get all available notifications for the vehicle.
A notification includes a message, notification date, read flag, date read.
Expand Down Expand Up @@ -158,7 +179,8 @@ async def get_trips_endpoint( # noqa: PLR0913, D417
) -> TripsResponseModel:
"""Get list of trips.
Retrieves a list of all trips between the given dates. The default data(route = False, summary = False) provides
Retrieves a list of all trips between the given dates. \n
The default data(route = False, summary = False) provides
a basic summary of each trip and includes Coaching message and electrical use.
Parameters
Expand All @@ -180,4 +202,6 @@ async def get_trips_endpoint( # noqa: PLR0913, D417
limit=limit,
offset=offset,
)
return await self._request_and_parse(TripsResponseModel, "GET", endpoint, vin=vin)
return await self._request_and_parse(

Check warning on line 205 in mytoyota/api.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/api.py#L205

Added line #L205 was not covered by tests
TripsResponseModel, "GET", endpoint, vin=vin
)
3 changes: 2 additions & 1 deletion mytoyota/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class MyT:
Connected services client class.
NOTE: Only tested with Toyota endpoints to this point. Do you have a Lexus/Subaru and are willing to help?
NOTE: Only tested with Toyota endpoints to this point.
Do you have a Lexus/Subaru and are willing to help?
"""

def __init__(
Expand Down
8 changes: 4 additions & 4 deletions mytoyota/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@

# API URLs
API_BASE_URL = "HTTPS://ctpa-oneapi.tceu-ctp-prd.toyotaconnectedeurope.io"
ACCESS_TOKEN_URL = "HTTPS://b2c-login.toyota-europe.com/oauth2/realms/root/realms/tme/access_token"
ACCESS_TOKEN_URL = (
"HTTPS://b2c-login.toyota-europe.com/oauth2/realms/root/realms/tme/access_token"
)
AUTHENTICATE_URL = "HTTPS://b2c-login.toyota-europe.com/json/realms/root/realms/tme/authenticate?authIndexType=service&authIndexValue=oneapp" # pylint: disable=C0301
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" # pylint: disable=C0301

Expand All @@ -55,9 +57,7 @@
VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT = "/v1/global/remote/electric/status"
VEHICLE_TELEMETRY_ENDPOINT = "/v3/telemetry"
VEHICLE_NOTIFICATION_HISTORY_ENDPOINT = "/v2/notification/history"
VEHICLE_TRIPS_ENDPOINT = (
"/v1/trips?from={from_date}&to={to_date}&route={route}&summary={summary}&limit={limit}&offset={offset}"
)
VEHICLE_TRIPS_ENDPOINT = "/v1/trips?from={from_date}&to={to_date}&route={route}&summary={summary}&limit={limit}&offset={offset}" # pylint: disable=C0301

# Timestamps
UNLOCK_TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
Expand Down
74 changes: 52 additions & 22 deletions mytoyota/controller.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""Toyota Connected Services Controller."""
import json
import logging
from datetime import datetime, timedelta
from http import HTTPStatus
import json
import logging
from os.path import exists, expanduser
from typing import Any, Dict, Optional
from urllib import parse
Expand All @@ -11,16 +11,23 @@
import httpx
import jwt

from mytoyota.const import ACCESS_TOKEN_URL, API_BASE_URL, AUTHENTICATE_URL, AUTHORIZE_URL
from mytoyota.const import (
ACCESS_TOKEN_URL,
API_BASE_URL,
AUTHENTICATE_URL,
AUTHORIZE_URL,
)
from mytoyota.exceptions import ToyotaApiError, ToyotaInternalError, ToyotaLoginError
from mytoyota.utils.logs import format_httpx_response

_LOGGER: logging.Logger = logging.getLogger(__package__)

CACHE_FILENAME: Optional[str] = expanduser("~/.cache/toyota_credentials_cache_contains_secrets")
CACHE_FILENAME: Optional[str] = expanduser(
"~/.cache/toyota_credentials_cache_contains_secrets"
)


# TODO There is an issue if you login with the application on a phone as all the tokens change.
# TODO There is an issue if you login with the application on a phone as all the tokens change. # pylint: disable=W0511
# This seems to work sometimes but no others. Needs investigation.


Expand All @@ -43,13 +50,15 @@ def __init__(self, username: str, password: str, timeout: int = 60) -> None:

# Do we have a cache file?
if CACHE_FILENAME and exists(CACHE_FILENAME):
with open(CACHE_FILENAME, "r") as f:
with open(CACHE_FILENAME, "r", encoding="utf-8") as f:
cache_data = json.load(f)
if self._username == cache_data["username"]:
self._token = cache_data["access_token"]
self._refresh_token = cache_data["refresh_token"]
self._uuid = cache_data["uuid"]
self._token_expiration = datetime.fromisoformat(cache_data["expiration"])
self._token_expiration = datetime.fromisoformat(

Check warning on line 59 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L53-L59

Added lines #L53 - L59 were not covered by tests
cache_data["expiration"]
)

async def login(self) -> None:
"""Perform first login."""
Expand All @@ -76,14 +85,21 @@ async def _authenticate(self):
for _ in range(10):
if "callbacks" in data:
for cb in data["callbacks"]:
if cb["type"] == "NameCallback" and cb["output"][0]["value"] == "User Name":
if (

Check warning on line 88 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L82-L88

Added lines #L82 - L88 were not covered by tests
cb["type"] == "NameCallback"
and cb["output"][0]["value"] == "User Name"
):
cb["input"][0]["value"] = self._username
elif cb["type"] == "PasswordCallback":
cb["input"][0]["value"] = self._password
resp = await client.post(self._authenticate_url, json=data) # , headers=standard_headers)
resp = await client.post(

Check warning on line 95 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L92-L95

Added lines #L92 - L95 were not covered by tests
self._authenticate_url, json=data
) # , headers=standard_headers)
_LOGGER.debug(format_httpx_response(resp))
if resp.status_code != HTTPStatus.OK:
raise ToyotaLoginError(f"Authentication Failed. {resp.status_code}, {resp.text}.")
raise ToyotaLoginError(

Check warning on line 100 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L98-L100

Added lines #L98 - L100 were not covered by tests
f"Authentication Failed. {resp.status_code}, {resp.text}."
)
data = resp.json()

Check warning on line 103 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L103

Added line #L103 was not covered by tests
# Wait for tokenId to be returned in response
if "tokenId" in data:
Expand All @@ -99,8 +115,12 @@ async def _authenticate(self):
)
_LOGGER.debug(format_httpx_response(resp))
if resp.status_code != HTTPStatus.FOUND:

Check warning on line 117 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L116-L117

Added lines #L116 - L117 were not covered by tests
raise ToyotaLoginError(f"Authorization failed. {resp.status_code}, {resp.text}.")
authentication_code = parse.parse_qs(httpx.URL(resp.headers.get("location")).query.decode())["code"]
raise ToyotaLoginError(
f"Authorization failed. {resp.status_code}, {resp.text}."
)
authentication_code = parse.parse_qs(

Check warning on line 121 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L121

Added line #L121 was not covered by tests
httpx.URL(resp.headers.get("location")).query.decode()
)["code"]

# Retrieve tokens
resp = await client.post(

Check warning on line 126 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L126

Added line #L126 was not covered by tests
Expand All @@ -116,7 +136,9 @@ async def _authenticate(self):
)
_LOGGER.debug(format_httpx_response(resp))
if resp.status_code != HTTPStatus.OK:
raise ToyotaLoginError(f"Token retrieval failed. {resp.status_code}, {resp.text}.")
raise ToyotaLoginError(

Check warning on line 139 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L137-L139

Added lines #L137 - L139 were not covered by tests
f"Token retrieval failed. {resp.status_code}, {resp.text}."
)

self._update_tokens(resp.json())

Check warning on line 143 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L143

Added line #L143 was not covered by tests

Expand All @@ -142,7 +164,9 @@ async def _refresh_tokens(self) -> None:
)
_LOGGER.debug(format_httpx_response(resp))
if resp.status_code != HTTPStatus.OK:

Check warning on line 166 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L165-L166

Added lines #L165 - L166 were not covered by tests
raise ToyotaLoginError(f"Token refresh failed. {resp.status_code}, {resp.text}.")
raise ToyotaLoginError(
f"Token refresh failed. {resp.status_code}, {resp.text}."
)

self._update_tokens(resp.json())

Check warning on line 171 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L171

Added line #L171 was not covered by tests

Expand All @@ -154,7 +178,9 @@ def _update_tokens(self, resp: json):
or "refresh_token" not in access_tokens
or "expires_in" not in access_tokens
):
raise ToyotaLoginError(f"Token retrieval failed. Missing Tokens. {resp.status_code}, {resp.text}.")
raise ToyotaLoginError(

Check warning on line 181 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L181

Added line #L181 was not covered by tests
f"Token retrieval failed. Missing Tokens. {resp.status_code}, {resp.text}."
)

self._token = access_tokens["access_token"]
self._refresh_token = access_tokens["refresh_token"]
Expand All @@ -164,10 +190,12 @@ def _update_tokens(self, resp: json):
options={"verify_signature": False},
audience="oneappsdkclient",
)["uuid"]
self._token_expiration = datetime.now() + timedelta(seconds=access_tokens["expires_in"])
self._token_expiration = datetime.now() + timedelta(

Check warning on line 193 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L193

Added line #L193 was not covered by tests
seconds=access_tokens["expires_in"]
)

if CACHE_FILENAME:
with open(CACHE_FILENAME, "w") as f:
with open(CACHE_FILENAME, "w", encoding="utf-8") as f:
f.write(

Check warning on line 199 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L197-L199

Added lines #L197 - L199 were not covered by tests
json.dumps(
{
Expand Down Expand Up @@ -230,7 +258,9 @@ async def request_raw( # noqa: PLR0913
]:
return response

Check warning on line 259 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L259

Added line #L259 was not covered by tests

raise ToyotaApiError(f"Request Failed. {response.status_code}, {response.text}.")
raise ToyotaApiError(

Check warning on line 261 in mytoyota/controller.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/controller.py#L261

Added line #L261 was not covered by tests
f"Request Failed. {response.status_code}, {response.text}."
)

async def request_json( # noqa: PLR0913
self,
Expand All @@ -247,12 +277,12 @@ async def request_json( # noqa: PLR0913
----
method (str): The HTTP method to use for the request.
endpoint (str): The endpoint to send the request to.
vin (Optional[str], optional): The VIN (Vehicle Identification Number) to include in the request.
Defaults to None.
vin (Optional[str], optional): The VIN (Vehicle Identification Number) to include
in the request. Defaults to None.
body (Optional[Dict[str, Any]], optional): The JSON body to include in the request.
Defaults to None.
params (Optional[Dict[str, Any]], optional): The query parameters to include in the request.
Defaults to None.
params (Optional[Dict[str, Any]], optional): The query parameters to
include in the request. Defaults to None.
headers (Optional[Dict[str, Any]], optional): The headers to include in the request.
Defaults to None.
Expand Down
26 changes: 20 additions & 6 deletions mytoyota/models/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
class Dashboard:
"""Information that may be found on a vehicles dashboard."""

# TODO do we want to supply last update times?
# TODO do we want to supply last update times? # pylint: disable=W0511

def __init__( # noqa: D417
self,
Expand All @@ -34,7 +34,11 @@ def __init__( # noqa: D417
def __repr__(self):
"""Representation of the Dashboard model."""
return " ".join(

Check warning on line 36 in mytoyota/models/dashboard.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/models/dashboard.py#L36

Added line #L36 was not covered by tests
[f"{k}={getattr(self, k)!s}" for k, v in type(self).__dict__.items() if isinstance(v, property)],
[
f"{k}={getattr(self, k)!s}"
for k, v in type(self).__dict__.items()
if isinstance(v, property)
],
)

@property
Expand All @@ -45,7 +49,9 @@ def odometer(self) -> float:
-------
The latest odometer reading in the current selected units
"""
return convert_distance(self._metric, self._telemetry.odometer.unit, self._telemetry.odometer.value)
return convert_distance(

Check warning on line 52 in mytoyota/models/dashboard.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/models/dashboard.py#L52

Added line #L52 was not covered by tests
self._metric, self._telemetry.odometer.unit, self._telemetry.odometer.value
)

@property
def fuel_level(self) -> int:
Expand Down Expand Up @@ -79,8 +85,12 @@ def fuel_range(self) -> Optional[float]:
If vehicle doesn't support fuel range returns None
"""
if self._electric:
return convert_distance(self._metric, self._electric.fuel_range.unit, self._electric.fuel_range.value)
elif self._telemetry.distance_to_empty:
return convert_distance(

Check warning on line 88 in mytoyota/models/dashboard.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/models/dashboard.py#L87-L88

Added lines #L87 - L88 were not covered by tests
self._metric,
self._electric.fuel_range.unit,
self._electric.fuel_range.value,
)
if self._telemetry.distance_to_empty:
return convert_distance(

Check warning on line 94 in mytoyota/models/dashboard.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/models/dashboard.py#L93-L94

Added lines #L93 - L94 were not covered by tests
self._metric,
self._telemetry.distance_to_empty.unit,
Expand All @@ -101,7 +111,11 @@ def battery_range(self) -> Optional[float]:
If vehicle doesn't support battery range returns None
"""
if self._electric:
return convert_distance(self._metric, self._electric.ev_range.unit, self._electric.ev_range.value)
return convert_distance(

Check warning on line 114 in mytoyota/models/dashboard.py

View check run for this annotation

Codecov / codecov/patch

mytoyota/models/dashboard.py#L113-L114

Added lines #L113 - L114 were not covered by tests
self._metric,
self._electric.ev_range.unit,
self._electric.ev_range.value,
)

return None

Expand Down
Loading

0 comments on commit 9164494

Please sign in to comment.