Renault code quality improvements (#55313)

* Use constants

* Drop entity_class for binary_sensor

* Move data property from RenaultDataEntity to RenaultSensor

* Update function description
This commit is contained in:
epenet 2021-08-27 12:12:09 +02:00 committed by GitHub
parent 259eeb3169
commit adab367f0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 33 deletions

View file

@ -18,7 +18,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType from homeassistant.helpers.typing import StateType
from .const import DOMAIN from .const import DOMAIN
from .renault_entities import RenaultDataEntity, RenaultEntityDescription, T from .renault_entities import RenaultDataEntity, RenaultEntityDescription
from .renault_hub import RenaultHub from .renault_hub import RenaultHub
@ -26,7 +26,7 @@ from .renault_hub import RenaultHub
class RenaultBinarySensorRequiredKeysMixin: class RenaultBinarySensorRequiredKeysMixin:
"""Mixin for required keys.""" """Mixin for required keys."""
entity_class: type[RenaultBinarySensor] on_key: str
on_value: StateType on_value: StateType
@ -47,7 +47,7 @@ async def async_setup_entry(
"""Set up the Renault entities from config entry.""" """Set up the Renault entities from config entry."""
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id] proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
entities: list[RenaultBinarySensor] = [ entities: list[RenaultBinarySensor] = [
description.entity_class(vehicle, description) RenaultBinarySensor(vehicle, description)
for vehicle in proxy.vehicles.values() for vehicle in proxy.vehicles.values()
for description in BINARY_SENSOR_TYPES for description in BINARY_SENSOR_TYPES
if description.coordinator in vehicle.coordinators if description.coordinator in vehicle.coordinators
@ -55,7 +55,9 @@ async def async_setup_entry(
async_add_entities(entities) async_add_entities(entities)
class RenaultBinarySensor(RenaultDataEntity[T], BinarySensorEntity): class RenaultBinarySensor(
RenaultDataEntity[KamereonVehicleBatteryStatusData], BinarySensorEntity
):
"""Mixin for binary sensor specific attributes.""" """Mixin for binary sensor specific attributes."""
entity_description: RenaultBinarySensorEntityDescription entity_description: RenaultBinarySensorEntityDescription
@ -63,26 +65,27 @@ class RenaultBinarySensor(RenaultDataEntity[T], BinarySensorEntity):
@property @property
def is_on(self) -> bool | None: def is_on(self) -> bool | None:
"""Return true if the binary sensor is on.""" """Return true if the binary sensor is on."""
return self.data == self.entity_description.on_value return (
self._get_data_attr(self.entity_description.on_key)
== self.entity_description.on_value
)
BINARY_SENSOR_TYPES: tuple[RenaultBinarySensorEntityDescription, ...] = ( BINARY_SENSOR_TYPES: tuple[RenaultBinarySensorEntityDescription, ...] = (
RenaultBinarySensorEntityDescription( RenaultBinarySensorEntityDescription(
key="plugged_in", key="plugged_in",
coordinator="battery", coordinator="battery",
data_key="plugStatus",
device_class=DEVICE_CLASS_PLUG, device_class=DEVICE_CLASS_PLUG,
entity_class=RenaultBinarySensor[KamereonVehicleBatteryStatusData],
name="Plugged In", name="Plugged In",
on_key="plugStatus",
on_value=PlugState.PLUGGED.value, on_value=PlugState.PLUGGED.value,
), ),
RenaultBinarySensorEntityDescription( RenaultBinarySensorEntityDescription(
key="charging", key="charging",
coordinator="battery", coordinator="battery",
data_key="chargingStatus",
device_class=DEVICE_CLASS_BATTERY_CHARGING, device_class=DEVICE_CLASS_BATTERY_CHARGING,
entity_class=RenaultBinarySensor[KamereonVehicleBatteryStatusData],
name="Charging", name="Charging",
on_key="chargingStatus",
on_value=ChargeState.CHARGE_IN_PROGRESS.value, on_value=ChargeState.CHARGE_IN_PROGRESS.value,
), ),
) )

View file

@ -1,4 +1,7 @@
"""Constants for the Renault component.""" """Constants for the Renault component."""
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
DOMAIN = "renault" DOMAIN = "renault"
CONF_LOCALE = "locale" CONF_LOCALE = "locale"
@ -7,8 +10,8 @@ CONF_KAMEREON_ACCOUNT_ID = "kamereon_account_id"
DEFAULT_SCAN_INTERVAL = 300 # 5 minutes DEFAULT_SCAN_INTERVAL = 300 # 5 minutes
PLATFORMS = [ PLATFORMS = [
"binary_sensor", BINARY_SENSOR_DOMAIN,
"sensor", SENSOR_DOMAIN,
] ]
DEVICE_CLASS_PLUG_STATE = "renault__plug_state" DEVICE_CLASS_PLUG_STATE = "renault__plug_state"

View file

@ -19,15 +19,12 @@ class RenaultRequiredKeysMixin:
"""Mixin for required keys.""" """Mixin for required keys."""
coordinator: str coordinator: str
data_key: str
@dataclass @dataclass
class RenaultEntityDescription(EntityDescription, RenaultRequiredKeysMixin): class RenaultEntityDescription(EntityDescription, RenaultRequiredKeysMixin):
"""Class describing Renault entities.""" """Class describing Renault entities."""
requires_fuel: bool | None = None
ATTR_LAST_UPDATE = "last_update" ATTR_LAST_UPDATE = "last_update"
@ -51,20 +48,17 @@ class RenaultDataEntity(CoordinatorEntity[Optional[T]], Entity):
self._attr_device_info = self.vehicle.device_info self._attr_device_info = self.vehicle.device_info
self._attr_unique_id = f"{self.vehicle.details.vin}_{description.key}".lower() self._attr_unique_id = f"{self.vehicle.details.vin}_{description.key}".lower()
@property def _get_data_attr(self, key: str) -> StateType:
def data(self) -> StateType: """Return the attribute value from the coordinator data."""
"""Return the state of this entity."""
if self.coordinator.data is None: if self.coordinator.data is None:
return None return None
return cast( return cast(StateType, getattr(self.coordinator.data, key))
StateType, getattr(self.coordinator.data, self.entity_description.data_key)
)
@property @property
def extra_state_attributes(self) -> Mapping[str, Any] | None: def extra_state_attributes(self) -> Mapping[str, Any] | None:
"""Return the state attributes of this entity.""" """Return the state attributes of this entity."""
if self.entity_description.coordinator == "battery" and self.coordinator.data: if self.entity_description.coordinator == "battery":
timestamp = getattr(self.coordinator.data, "timestamp") last_update = self._get_data_attr("timestamp")
if timestamp: if last_update:
return {ATTR_LAST_UPDATE: timestamp} return {ATTR_LAST_UPDATE: last_update}
return None return None

View file

@ -50,6 +50,7 @@ from .renault_hub import RenaultHub
class RenaultSensorRequiredKeysMixin: class RenaultSensorRequiredKeysMixin:
"""Mixin for required keys.""" """Mixin for required keys."""
data_key: str
entity_class: type[RenaultSensor] entity_class: type[RenaultSensor]
@ -59,8 +60,9 @@ class RenaultSensorEntityDescription(
): ):
"""Class describing Renault sensor entities.""" """Class describing Renault sensor entities."""
icon_lambda: Callable[[RenaultDataEntity[T]], str] | None = None icon_lambda: Callable[[RenaultSensor[T]], str] | None = None
value_lambda: Callable[[RenaultDataEntity[T]], StateType] | None = None requires_fuel: bool | None = None
value_lambda: Callable[[RenaultSensor[T]], StateType] | None = None
async def async_setup_entry( async def async_setup_entry(
@ -85,6 +87,11 @@ class RenaultSensor(RenaultDataEntity[T], SensorEntity):
entity_description: RenaultSensorEntityDescription entity_description: RenaultSensorEntityDescription
@property
def data(self) -> StateType:
"""Return the state of this entity."""
return self._get_data_attr(self.entity_description.data_key)
@property @property
def icon(self) -> str | None: def icon(self) -> str | None:
"""Icon handling.""" """Icon handling."""
@ -102,49 +109,49 @@ class RenaultSensor(RenaultDataEntity[T], SensorEntity):
return self.entity_description.value_lambda(self) return self.entity_description.value_lambda(self)
def _get_charge_mode_icon(entity: RenaultDataEntity[T]) -> str: def _get_charge_mode_icon(entity: RenaultSensor[T]) -> str:
"""Return the icon of this entity.""" """Return the icon of this entity."""
if entity.data == "schedule_mode": if entity.data == "schedule_mode":
return "mdi:calendar-clock" return "mdi:calendar-clock"
return "mdi:calendar-remove" return "mdi:calendar-remove"
def _get_charging_power(entity: RenaultDataEntity[T]) -> StateType: def _get_charging_power(entity: RenaultSensor[T]) -> StateType:
"""Return the charging_power of this entity.""" """Return the charging_power of this entity."""
if entity.vehicle.details.reports_charging_power_in_watts(): if entity.vehicle.details.reports_charging_power_in_watts():
return cast(float, entity.data) / 1000 return cast(float, entity.data) / 1000
return entity.data return entity.data
def _get_charge_state_formatted(entity: RenaultDataEntity[T]) -> str | None: def _get_charge_state_formatted(entity: RenaultSensor[T]) -> str | None:
"""Return the charging_status of this entity.""" """Return the charging_status of this entity."""
data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data) data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data)
charging_status = data.get_charging_status() if data else None charging_status = data.get_charging_status() if data else None
return charging_status.name.lower() if charging_status else None return charging_status.name.lower() if charging_status else None
def _get_charge_state_icon(entity: RenaultDataEntity[T]) -> str: def _get_charge_state_icon(entity: RenaultSensor[T]) -> str:
"""Return the icon of this entity.""" """Return the icon of this entity."""
if entity.data == ChargeState.CHARGE_IN_PROGRESS.value: if entity.data == ChargeState.CHARGE_IN_PROGRESS.value:
return "mdi:flash" return "mdi:flash"
return "mdi:flash-off" return "mdi:flash-off"
def _get_plug_state_formatted(entity: RenaultDataEntity[T]) -> str | None: def _get_plug_state_formatted(entity: RenaultSensor[T]) -> str | None:
"""Return the plug_status of this entity.""" """Return the plug_status of this entity."""
data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data) data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data)
plug_status = data.get_plug_status() if data else None plug_status = data.get_plug_status() if data else None
return plug_status.name.lower() if plug_status else None return plug_status.name.lower() if plug_status else None
def _get_plug_state_icon(entity: RenaultDataEntity[T]) -> str: def _get_plug_state_icon(entity: RenaultSensor[T]) -> str:
"""Return the icon of this entity.""" """Return the icon of this entity."""
if entity.data == PlugState.PLUGGED.value: if entity.data == PlugState.PLUGGED.value:
return "mdi:power-plug" return "mdi:power-plug"
return "mdi:power-plug-off" return "mdi:power-plug-off"
def _get_rounded_value(entity: RenaultDataEntity[T]) -> float: def _get_rounded_value(entity: RenaultSensor[T]) -> float:
"""Return the icon of this entity.""" """Return the icon of this entity."""
return round(cast(float, entity.data)) return round(cast(float, entity.data))