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

Renault code quality improvements #55454

Merged
merged 7 commits into from
Aug 31, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion homeassistant/components/renault/renault_coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
KamereonResponseException,
NotSupportedException,
)
from renault_api.kamereon.models import KamereonVehicleDataAttributes

from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

T = TypeVar("T")
T = TypeVar("T", bound=KamereonVehicleDataAttributes)


class RenaultDataUpdateCoordinator(DataUpdateCoordinator[T]):
Expand Down
7 changes: 2 additions & 5 deletions homeassistant/components/renault/renault_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@

from collections.abc import Mapping
from dataclasses import dataclass
from typing import Any, Optional, TypeVar, cast

from renault_api.kamereon.models import KamereonVehicleDataAttributes
from typing import Any, Optional, cast

from homeassistant.helpers.entity import Entity, EntityDescription
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from .renault_coordinator import T
from .renault_vehicle import RenaultVehicleProxy


Expand All @@ -28,8 +27,6 @@ class RenaultEntityDescription(EntityDescription, RenaultRequiredKeysMixin):

ATTR_LAST_UPDATE = "last_update"

T = TypeVar("T", bound=KamereonVehicleDataAttributes)


class RenaultDataEntity(CoordinatorEntity[Optional[T]], Entity):
"""Implementation of a Renault entity with a data coordinator."""
Expand Down
107 changes: 51 additions & 56 deletions homeassistant/components/renault/renault_vehicle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
from __future__ import annotations

import asyncio
from collections.abc import Awaitable
from dataclasses import dataclass
from datetime import timedelta
import logging
from typing import cast
from typing import Callable, cast

from renault_api.kamereon import models
from renault_api.renault_vehicle import RenaultVehicle
Expand All @@ -25,6 +27,20 @@
LOGGER = logging.getLogger(__name__)


@dataclass
class RenaultCoordinatorDescription:
"""Class describing Renault coordinators."""

endpoint: str
key: str
update_method: Callable[
[RenaultVehicle],
Callable[[], Awaitable[models.KamereonVehicleDataAttributes]],
]
# Optional keys
requires_electricity: bool = False


class RenaultVehicleProxy:
"""Handle vehicle communication with Renault servers."""

Expand Down Expand Up @@ -61,48 +77,23 @@ def device_info(self) -> DeviceInfo:
return self._device_info

async def async_initialise(self) -> None:
"""Load available sensors."""
if await self.endpoint_available("cockpit"):
self.coordinators["cockpit"] = RenaultDataUpdateCoordinator(
"""Load available coordinators."""
self.coordinators = {
coord.key: RenaultDataUpdateCoordinator(
self.hass,
LOGGER,
# Name of the data. For logging purposes.
name=f"{self.details.vin} cockpit",
update_method=self.get_cockpit,
name=f"{self.details.vin} {coord.key}",
update_method=coord.update_method(self._vehicle),
# Polling interval. Will only be polled if there are subscribers.
update_interval=self._scan_interval,
)
if await self.endpoint_available("hvac-status"):
self.coordinators["hvac_status"] = RenaultDataUpdateCoordinator(
self.hass,
LOGGER,
# Name of the data. For logging purposes.
name=f"{self.details.vin} hvac_status",
update_method=self.get_hvac_status,
# Polling interval. Will only be polled if there are subscribers.
update_interval=self._scan_interval,
for coord in COORDINATORS
if (
self.details.supports_endpoint(coord.endpoint)
and (not coord.requires_electricity or self.details.uses_electricity())
)
if self.details.uses_electricity():
if await self.endpoint_available("battery-status"):
self.coordinators["battery"] = RenaultDataUpdateCoordinator(
self.hass,
LOGGER,
# Name of the data. For logging purposes.
name=f"{self.details.vin} battery",
update_method=self.get_battery_status,
# Polling interval. Will only be polled if there are subscribers.
update_interval=self._scan_interval,
)
if await self.endpoint_available("charge-mode"):
self.coordinators["charge_mode"] = RenaultDataUpdateCoordinator(
self.hass,
LOGGER,
# Name of the data. For logging purposes.
name=f"{self.details.vin} charge_mode",
update_method=self.get_charge_mode,
# Polling interval. Will only be polled if there are subscribers.
update_interval=self._scan_interval,
)
}
# Check all coordinators
await asyncio.gather(
*(
Expand Down Expand Up @@ -130,24 +121,28 @@ async def async_initialise(self) -> None:
)
del self.coordinators[key]

async def endpoint_available(self, endpoint: str) -> bool:
"""Ensure the endpoint is available to avoid unnecessary queries."""
return await self._vehicle.supports_endpoint(
endpoint
) and await self._vehicle.has_contract_for_endpoint(endpoint)

async def get_battery_status(self) -> models.KamereonVehicleBatteryStatusData:
"""Get battery status information from vehicle."""
return await self._vehicle.get_battery_status()

async def get_charge_mode(self) -> models.KamereonVehicleChargeModeData:
"""Get charge mode information from vehicle."""
return await self._vehicle.get_charge_mode()

async def get_cockpit(self) -> models.KamereonVehicleCockpitData:
"""Get cockpit information from vehicle."""
return await self._vehicle.get_cockpit()

async def get_hvac_status(self) -> models.KamereonVehicleHvacStatusData:
"""Get hvac status information from vehicle."""
return await self._vehicle.get_hvac_status()
COORDINATORS: tuple[RenaultCoordinatorDescription, ...] = (
RenaultCoordinatorDescription(
endpoint="cockpit",
key="cockpit",
update_method=lambda x: x.get_cockpit,
),
RenaultCoordinatorDescription(
endpoint="hvac-status",
key="hvac_status",
update_method=lambda x: x.get_hvac_status,
),
RenaultCoordinatorDescription(
endpoint="battery-status",
key="battery",
requires_electricity=True,
update_method=lambda x: x.get_battery_status,
),
RenaultCoordinatorDescription(
endpoint="charge-mode",
key="charge_mode",
requires_electricity=True,
update_method=lambda x: x.get_charge_mode,
),
)
5 changes: 3 additions & 2 deletions homeassistant/components/renault/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
DEVICE_CLASS_PLUG_STATE,
DOMAIN,
)
from .renault_entities import RenaultDataEntity, RenaultEntityDescription, T
from .renault_coordinator import T
from .renault_entities import RenaultDataEntity, RenaultEntityDescription
from .renault_hub import RenaultHub


Expand All @@ -61,7 +62,7 @@ class RenaultSensorEntityDescription(
"""Class describing Renault sensor entities."""

icon_lambda: Callable[[RenaultSensor[T]], str] | None = None
requires_fuel: bool | None = None
requires_fuel: bool = False
value_lambda: Callable[[RenaultSensor[T]], StateType] | None = None


Expand Down