Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new mytoyota api endpoints #198

Merged
merged 71 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
4ef5b3a
poetry update and use stub files in dev dependencies for better hints
CM000n Jan 1, 2024
139e057
update mytoyota dependency in manifest file
CM000n Jan 1, 2024
dae4a5b
fix implicit string concatenation
CM000n Jan 1, 2024
774e8d0
adapt config flow to new api
CM000n Jan 1, 2024
dd96fc7
adopt statistics gathering to upcoming mytoyota changes
CM000n Jan 2, 2024
9f5835a
adopt device tracker to new API
CM000n Jan 2, 2024
07eede1
update manifest file
CM000n Jan 2, 2024
60bac8c
add statistic to base entity
CM000n Jan 3, 2024
cd2af30
bump version
CM000n Jan 3, 2024
8086e1f
using brand from vehicle info
CM000n Jan 3, 2024
bebc384
simplify genrating of device tracker
CM000n Jan 3, 2024
6cc1fac
bump required minimum mytoyota version to 1.1.0
CM000n Jan 3, 2024
1f97c9e
remove unused binary sensors for now
CM000n Jan 3, 2024
c6ac342
simplify capability check
CM000n Jan 3, 2024
3576f64
adopt binary sensors to new api models
CM000n Jan 3, 2024
87e497c
fix import error
CM000n Jan 3, 2024
d9ad89c
use last_parked capability for generating device_tracker
CM000n Jan 3, 2024
310f7e4
make metric value choise a requirement
CM000n Jan 4, 2024
153d324
make metric value choise a requirement
CM000n Jan 4, 2024
50fd3b0
add translations
CM000n Jan 4, 2024
d8ca62c
bump minmum required mytoyota version
CM000n Jan 6, 2024
f2d7164
invert binary sensor logic
CM000n Jan 6, 2024
c6e5110
merge master
CM000n Jan 8, 2024
d0b2d31
only create trunk status binary_sensor if bonnet_status capability is…
CM000n Jan 8, 2024
758eb67
run pre-commit on all files
CM000n Jan 8, 2024
f27b42d
return None if try block fails
CM000n Jan 8, 2024
eeb1779
increase update_interval to 5 minutes
CM000n Jan 8, 2024
1eec460
adjust driver door lock icon
CM000n Jan 8, 2024
588d6a3
make metric value information available for further steps
CM000n Jan 8, 2024
241113c
adopt statistics sensors to new api
CM000n Jan 8, 2024
4fb4ee6
update statistics utils and delete unsused constants
CM000n Jan 8, 2024
c9cda60
add vin sensor
CM000n Jan 8, 2024
97de4bd
display all vehicle informations in vin sensor
CM000n Jan 9, 2024
30fad24
display ev summary also for pure electric vehicles
CM000n Jan 9, 2024
5ac3feb
return timdelta and date as string
CM000n Jan 9, 2024
e325833
add odometer and fuel sensors
CM000n Jan 9, 2024
6af3f53
clean up sensor translations
CM000n Jan 9, 2024
5c1f2d3
format vin sensor attributes
CM000n Jan 9, 2024
a7e1bba
use car_model_name
CM000n Jan 9, 2024
87f30c7
make battery_level sensor available for all ev vehicles
CM000n Jan 9, 2024
c20a4ae
use upper case for asi_code and imei
CM000n Jan 9, 2024
6c4438a
fix battery_level sensor
CM000n Jan 9, 2024
8d05180
return only true capabilities
CM000n Jan 9, 2024
aec7cda
add battery_range
CM000n Jan 9, 2024
90ded8d
add total_range
CM000n Jan 9, 2024
3c514bd
add battery_range_ac
CM000n Jan 9, 2024
e8fc10d
fix unpacking
CM000n Jan 9, 2024
d5cc6c5
reurn dict instead of list
CM000n Jan 9, 2024
fe5455d
mask pii data in attributes
CM000n Jan 9, 2024
119234e
round range and level values
CM000n Jan 9, 2024
8df5b43
bump minimum required mytoyota version to 1.1.3
CM000n Jan 9, 2024
fd03a97
reduce line-length
CM000n Jan 9, 2024
2780ab1
no need for masking Katashiki_code
CM000n Jan 10, 2024
e1919aa
add duration and distance to summary attributes
CM000n Jan 10, 2024
2d59460
remove redundant vin information in attributes
CM000n Jan 10, 2024
3d531ac
remove redundant information
CM000n Jan 10, 2024
c9427fd
rename fuel consumption
CM000n Jan 10, 2024
b41eb69
bump minimum required mytoyota version to 1.2.0
CM000n Jan 11, 2024
a8283c7
add average_fuel_consumed to vin sensor attributes
CM000n Jan 11, 2024
3619f37
use dictionary merging
CM000n Jan 11, 2024
0daba1d
Make use of new helper functions for statistics
CM000n Jan 11, 2024
279c9fe
Update readme
CM000n Jan 11, 2024
785aa47
generate battery sensors only for ev vehicles
CM000n Jan 11, 2024
8c53722
Merge branch 'enhancement/use_new_mytoyota_api' of github.com:DurgNom…
CM000n Jan 11, 2024
ec683f2
Use Mapping for brand names
CM000n Jan 11, 2024
69ad37f
create odometer only when telemetry capable
CM000n Jan 11, 2024
ad00a00
Update French translations (#203)
pierrebelloy Jan 11, 2024
ec2b3bc
Use same condition for ev vehicles like in mytoyota lib
CM000n Jan 11, 2024
37f1e5f
Merge branch 'enhancement/use_new_mytoyota_api' of github.com:DurgNom…
CM000n Jan 11, 2024
d08a2b1
use same condition for last_parked like in mytoyota lib
CM000n Jan 11, 2024
d661f35
create statistics sensors by default for now
CM000n Jan 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 54 additions & 63 deletions custom_components/toyota/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,33 @@
import asyncio.exceptions as asyncioexceptions
import logging
from datetime import timedelta
from typing import Any, Optional, TypedDict
from typing import Optional, TypedDict

import httpcore
import httpx
from arrow import Arrow
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_EMAIL,
CONF_PASSWORD,
CONF_UNIT_SYSTEM_IMPERIAL,
CONF_UNIT_SYSTEM_METRIC,
)
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from mytoyota import MyT
from mytoyota.exceptions import ToyotaApiError, ToyotaInternalError, ToyotaLoginError
from mytoyota.models.summary import Summary, SummaryType
from mytoyota.models.vehicle import Vehicle

from .const import (
CONF_UNIT_SYSTEM_IMPERIAL_LITERS,
CONF_USE_LITERS_PER_100_MILES,
DOMAIN,
PLATFORMS,
STARTUP_MESSAGE,
)
from .const import CONF_METRIC_VALUES, DOMAIN, PLATFORMS, STARTUP_MESSAGE

_LOGGER = logging.getLogger(__name__)


class StatisticsData(TypedDict):
"""Representing Statistics data."""

day: list[dict[str, Any]]
week: list[dict[str, Any]]
month: list[dict[str, Any]]
year: list[dict[str, Any]]
day: Optional[Summary]
week: Optional[Summary]
month: Optional[Summary]
year: Optional[Summary]


class VehicleData(TypedDict):
Expand All @@ -60,12 +51,11 @@ async def async_setup_entry( # pylint: disable=too-many-statements

email = entry.data[CONF_EMAIL]
password = entry.data[CONF_PASSWORD]
use_liters = entry.options.get(CONF_USE_LITERS_PER_100_MILES, False)
use_metric_values = entry.options.get(CONF_METRIC_VALUES, True)

client = MyT(
username=email,
password=password,
disable_locale_check=True,
)

try:
Expand All @@ -75,49 +65,52 @@ async def async_setup_entry( # pylint: disable=too-many-statements
except (httpx.ConnectTimeout, httpcore.ConnectTimeout) as ex:
raise ConfigEntryNotReady("Unable to connect to Toyota Connected Services") from ex

async def async_get_vehicle_data() -> list[VehicleData]:
async def async_get_vehicle_data() -> Optional[list[VehicleData]]:
"""Fetch vehicle data from Toyota API."""
try:
vehicles = await asyncio.wait_for(client.get_vehicles(), 15)
vehicles = await asyncio.wait_for(client.get_vehicles(metric=use_metric_values), 15)
vehicle_informations: list[VehicleData] = []
for vehicle in vehicles:
vehicle_status = await client.get_vehicle_status(vehicle)
_LOGGER.debug(vars(vehicle_status))

vehicle_data = VehicleData(data=vehicle_status, statistics=None)

unit_system_map = {
False: CONF_UNIT_SYSTEM_IMPERIAL,
True: CONF_UNIT_SYSTEM_IMPERIAL_LITERS,
}
unit = CONF_UNIT_SYSTEM_METRIC if vehicle_status.dashboard.is_metric else unit_system_map[use_liters]

_LOGGER.debug(f"The car is reporting data in {unit}")
if use_liters and not vehicle_status.dashboard.is_metric:
_LOGGER.debug("Getting statistics in imperial and L/100 miles")
elif not vehicle_status.dashboard.is_metric:
_LOGGER.debug("Getting statistics in imperial and MPG")

if vehicle_status.is_connected_services_enabled and vehicle_status.vin is not None:
# Use parallel request to get car statistics.
driving_statistics = await asyncio.gather(
client.get_driving_statistics(vehicle_status.vin, interval="day", unit=unit),
client.get_driving_statistics(vehicle_status.vin, interval="isoweek", unit=unit),
client.get_driving_statistics(vehicle_status.vin, unit=unit),
client.get_driving_statistics(vehicle_status.vin, interval="year", unit=unit),
)

vehicle_data["statistics"] = StatisticsData(
day=driving_statistics[0],
week=driving_statistics[1],
month=driving_statistics[2],
year=driving_statistics[3],
)

vehicle_informations.append(vehicle_data)

_LOGGER.debug(vehicle_informations)
return vehicle_informations
if vehicles is not None:
for vehicle in vehicles:
await vehicle.update()
vehicle_data = VehicleData(data=vehicle, statistics=None)

if vehicle.vin is not None:
# Use parallel request to get car statistics.
driving_statistics = await asyncio.gather(
vehicle.get_summary(
Arrow.now().date(),
Arrow.now().date(),
summary_type=SummaryType.DAILY,
),
vehicle.get_summary(
Arrow.now().floor("week").date(),
Arrow.now().date(),
summary_type=SummaryType.WEEKLY,
),
vehicle.get_summary(
Arrow.now().floor("month").date(),
Arrow.now().date(),
summary_type=SummaryType.MONTHLY,
),
vehicle.get_summary(
Arrow.now().floor("year").date(),
Arrow.now().date(),
summary_type=SummaryType.YEARLY,
),
)

vehicle_data["statistics"] = StatisticsData(
day=next(iter(driving_statistics[0] or []), None),
week=next(iter(driving_statistics[1] or []), None),
month=next(iter(driving_statistics[2] or []), None),
year=next(iter(driving_statistics[3] or []), None),
)

vehicle_informations.append(vehicle_data)

_LOGGER.debug(vehicle_informations)
return vehicle_informations

except ToyotaLoginError as ex:
_LOGGER.error(ex)
Expand All @@ -132,9 +125,7 @@ async def async_get_vehicle_data() -> list[VehicleData]:
asyncioexceptions.TimeoutError,
httpx.ReadTimeout,
) as ex:
raise UpdateFailed(
"Update canceled! Toyota's API was too slow to respond." " Will try again later..."
) from ex
raise UpdateFailed("Update canceled! Toyota's API was too slow to respond. Will try again later...") from ex

coordinator = DataUpdateCoordinator(
hass,
Expand Down
10 changes: 3 additions & 7 deletions custom_components/toyota/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
from mytoyota.exceptions import ToyotaInvalidUsername, ToyotaLoginError

# https://github.com/PyCQA/pylint/issues/3202
from .const import ( # pylint: disable=unused-import
CONF_USE_LITERS_PER_100_MILES,
DOMAIN,
)
from .const import CONF_METRIC_VALUES, DOMAIN # pylint: disable=unused-import

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -41,7 +38,6 @@ async def async_step_user(self, user_input=None) -> FlowResult:
client = MyT(
username=user_input[CONF_EMAIL],
password=user_input[CONF_PASSWORD],
disable_locale_check=True,
)

await client.login()
Expand Down Expand Up @@ -86,8 +82,8 @@ async def async_step_init(self, user_input=None) -> FlowResult:
data_schema=vol.Schema(
{
vol.Optional(
CONF_USE_LITERS_PER_100_MILES,
default=self.config_entry.options.get(CONF_USE_LITERS_PER_100_MILES, False),
CONF_METRIC_VALUES,
default=self.config_entry.options.get(CONF_METRIC_VALUES, True),
): bool,
}
),
Expand Down
3 changes: 1 addition & 2 deletions custom_components/toyota/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"europe",
]
CONF_UNIT_SYSTEM_IMPERIAL_LITERS = "imperial_liters"
CONF_USE_LITERS_PER_100_MILES = "use_liters"
CONF_METRIC_VALUES = "use_metric_values"

# DEFAULTS
DEFAULT_LOCALE = "en-gb"
Expand All @@ -40,7 +40,6 @@
HIGHWAY_DISTANCE = "highwayDistanceInKm"
HIGHWAY_DISTANCE_PERCENTAGE = "highwayDistancePercentage"
HYBRID = "hybrid"
IMAGE = "imageUrl"
LAST_UPDATED = "last_updated"
LICENSE_PLATE = "licensePlate"
MAX_SPEED = "maxSpeedInKmph"
Expand Down
14 changes: 7 additions & 7 deletions custom_components/toyota/device_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

from . import VehicleData
from .const import DOMAIN, ICON_PARKING, IMAGE
from .const import DOMAIN, ICON_PARKING
from .entity import ToyotaBaseEntity

PARKING_TRACKER_DESCRIPTION: EntityDescription = EntityDescription(
Expand All @@ -37,7 +37,7 @@ async def async_setup_entry(
description=PARKING_TRACKER_DESCRIPTION,
)
for index, vehicle in enumerate(coordinator.data)
if vehicle["data"].is_connected_services_enabled and vehicle["data"].parkinglocation
if vehicle["data"].location
)


Expand All @@ -49,14 +49,14 @@ class ToyotaParkingTracker(ToyotaBaseEntity, TrackerEntity):
@property
def latitude(self) -> Optional[float]:
"""Return latitude value of the device."""
parking = self.coordinator.data[self.index]["data"].parkinglocation
return parking.latitude if parking else None
location = self.vehicle.location
return location.latitude if location else None

@property
def longitude(self) -> Optional[float]:
"""Return longitude value of the device."""
parking = self.coordinator.data[self.index]["data"].parkinglocation
return parking.longitude if parking else None
location = self.vehicle.location
return location.longitude if location else None

@property
def source_type(self) -> str:
Expand All @@ -66,4 +66,4 @@ def source_type(self) -> str:
@property
def entity_picture(self) -> Optional[str]:
"""Return entity picture."""
return self.vehicle.details.get(IMAGE)
return self.vehicle._vehicle_info.image
15 changes: 9 additions & 6 deletions custom_components/toyota/entity.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Custom coordinator entity base classes for Toyota Connected Services integration."""
from __future__ import annotations

from typing import Optional

from homeassistant.core import callback
from homeassistant.helpers.entity import DeviceInfo, EntityDescription
from homeassistant.helpers.update_coordinator import (
Expand All @@ -9,7 +11,7 @@
)
from mytoyota.models.vehicle import Vehicle

from . import VehicleData
from . import StatisticsData, VehicleData
from .const import DOMAIN


Expand All @@ -29,22 +31,23 @@ def __init__(
super().__init__(coordinator)

self.index = vehicle_index
self.entity_description = description
self.vehicle: Vehicle = coordinator.data[self.index]["data"]
self.statistics: Optional[StatisticsData] = coordinator.data[self.index]["statistics"]

self._attr_unique_id = f"{entry_id}_{self.vehicle.vin}/{description.key}"

self._attr_unique_id = f"{entry_id}_{self.vehicle.vin}/{self.entity_description.key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.vehicle.vin)},
name=self.vehicle.alias,
model=self.vehicle.details.get("modelName"),
manufacturer=DOMAIN.capitalize(),
model=self.vehicle._vehicle_info.car_model_name,
manufacturer=self.vehicle._vehicle_info.brand,
)
self.entity_description = description

@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self.vehicle = self.coordinator.data[self.index]["data"]
self.statistics = self.coordinator.data[self.index]["statistics"]
super()._handle_coordinator_update()

async def async_added_to_hass(self) -> None:
Expand Down
16 changes: 12 additions & 4 deletions custom_components/toyota/manifest.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
{
"domain": "toyota",
"name": "Toyota Connected Services",
"after_dependencies": ["cloud", "http"],
"codeowners": ["@DurgNomis-drol"],
"after_dependencies": [
"cloud",
"http"
],
"codeowners": [
"@DurgNomis-drol"
],
"config_flow": true,
"documentation": "https://github.com/DurgNomis-drol/ha_toyota",
"iot_class": "cloud_polling",
"issue_tracker": "https://github.com/DurgNomis-drol/ha_toyota/issues",
"requirements": ["mytoyota==0.9.3", "arrow"],
"version": "v1.3.0"
"requirements": [
"mytoyota>=1.1",
"arrow"
],
"version": "v2.0.0"
}
Loading