From adab367f0e8c48a68b4dffd0783351b0072fbd0a Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 27 Aug 2021 12:12:09 +0200 Subject: [PATCH] Renault code quality improvements (#55313) * Use constants * Drop entity_class for binary_sensor * Move data property from RenaultDataEntity to RenaultSensor * Update function description --- .../components/renault/binary_sensor.py | 21 +++++++++------- homeassistant/components/renault/const.py | 7 ++++-- .../components/renault/renault_entities.py | 20 ++++++--------- homeassistant/components/renault/sensor.py | 25 ++++++++++++------- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/homeassistant/components/renault/binary_sensor.py b/homeassistant/components/renault/binary_sensor.py index 17a735f8bc7..2799289fc1d 100644 --- a/homeassistant/components/renault/binary_sensor.py +++ b/homeassistant/components/renault/binary_sensor.py @@ -18,7 +18,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType from .const import DOMAIN -from .renault_entities import RenaultDataEntity, RenaultEntityDescription, T +from .renault_entities import RenaultDataEntity, RenaultEntityDescription from .renault_hub import RenaultHub @@ -26,7 +26,7 @@ from .renault_hub import RenaultHub class RenaultBinarySensorRequiredKeysMixin: """Mixin for required keys.""" - entity_class: type[RenaultBinarySensor] + on_key: str on_value: StateType @@ -47,7 +47,7 @@ async def async_setup_entry( """Set up the Renault entities from config entry.""" proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id] entities: list[RenaultBinarySensor] = [ - description.entity_class(vehicle, description) + RenaultBinarySensor(vehicle, description) for vehicle in proxy.vehicles.values() for description in BINARY_SENSOR_TYPES if description.coordinator in vehicle.coordinators @@ -55,7 +55,9 @@ async def async_setup_entry( async_add_entities(entities) -class RenaultBinarySensor(RenaultDataEntity[T], BinarySensorEntity): +class RenaultBinarySensor( + RenaultDataEntity[KamereonVehicleBatteryStatusData], BinarySensorEntity +): """Mixin for binary sensor specific attributes.""" entity_description: RenaultBinarySensorEntityDescription @@ -63,26 +65,27 @@ class RenaultBinarySensor(RenaultDataEntity[T], BinarySensorEntity): @property def is_on(self) -> bool | None: """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, ...] = ( RenaultBinarySensorEntityDescription( key="plugged_in", coordinator="battery", - data_key="plugStatus", device_class=DEVICE_CLASS_PLUG, - entity_class=RenaultBinarySensor[KamereonVehicleBatteryStatusData], name="Plugged In", + on_key="plugStatus", on_value=PlugState.PLUGGED.value, ), RenaultBinarySensorEntityDescription( key="charging", coordinator="battery", - data_key="chargingStatus", device_class=DEVICE_CLASS_BATTERY_CHARGING, - entity_class=RenaultBinarySensor[KamereonVehicleBatteryStatusData], name="Charging", + on_key="chargingStatus", on_value=ChargeState.CHARGE_IN_PROGRESS.value, ), ) diff --git a/homeassistant/components/renault/const.py b/homeassistant/components/renault/const.py index 0987d1829ed..824779a4d3e 100644 --- a/homeassistant/components/renault/const.py +++ b/homeassistant/components/renault/const.py @@ -1,4 +1,7 @@ """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" CONF_LOCALE = "locale" @@ -7,8 +10,8 @@ CONF_KAMEREON_ACCOUNT_ID = "kamereon_account_id" DEFAULT_SCAN_INTERVAL = 300 # 5 minutes PLATFORMS = [ - "binary_sensor", - "sensor", + BINARY_SENSOR_DOMAIN, + SENSOR_DOMAIN, ] DEVICE_CLASS_PLUG_STATE = "renault__plug_state" diff --git a/homeassistant/components/renault/renault_entities.py b/homeassistant/components/renault/renault_entities.py index 4e364c9d5d1..003103d52d3 100644 --- a/homeassistant/components/renault/renault_entities.py +++ b/homeassistant/components/renault/renault_entities.py @@ -19,15 +19,12 @@ class RenaultRequiredKeysMixin: """Mixin for required keys.""" coordinator: str - data_key: str @dataclass class RenaultEntityDescription(EntityDescription, RenaultRequiredKeysMixin): """Class describing Renault entities.""" - requires_fuel: bool | None = None - 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_unique_id = f"{self.vehicle.details.vin}_{description.key}".lower() - @property - def data(self) -> StateType: - """Return the state of this entity.""" + def _get_data_attr(self, key: str) -> StateType: + """Return the attribute value from the coordinator data.""" if self.coordinator.data is None: return None - return cast( - StateType, getattr(self.coordinator.data, self.entity_description.data_key) - ) + return cast(StateType, getattr(self.coordinator.data, key)) @property def extra_state_attributes(self) -> Mapping[str, Any] | None: """Return the state attributes of this entity.""" - if self.entity_description.coordinator == "battery" and self.coordinator.data: - timestamp = getattr(self.coordinator.data, "timestamp") - if timestamp: - return {ATTR_LAST_UPDATE: timestamp} + if self.entity_description.coordinator == "battery": + last_update = self._get_data_attr("timestamp") + if last_update: + return {ATTR_LAST_UPDATE: last_update} return None diff --git a/homeassistant/components/renault/sensor.py b/homeassistant/components/renault/sensor.py index 982e16f3b13..537d708f391 100644 --- a/homeassistant/components/renault/sensor.py +++ b/homeassistant/components/renault/sensor.py @@ -50,6 +50,7 @@ from .renault_hub import RenaultHub class RenaultSensorRequiredKeysMixin: """Mixin for required keys.""" + data_key: str entity_class: type[RenaultSensor] @@ -59,8 +60,9 @@ class RenaultSensorEntityDescription( ): """Class describing Renault sensor entities.""" - icon_lambda: Callable[[RenaultDataEntity[T]], str] | None = None - value_lambda: Callable[[RenaultDataEntity[T]], StateType] | None = None + icon_lambda: Callable[[RenaultSensor[T]], str] | None = None + requires_fuel: bool | None = None + value_lambda: Callable[[RenaultSensor[T]], StateType] | None = None async def async_setup_entry( @@ -85,6 +87,11 @@ class RenaultSensor(RenaultDataEntity[T], SensorEntity): 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 def icon(self) -> str | None: """Icon handling.""" @@ -102,49 +109,49 @@ class RenaultSensor(RenaultDataEntity[T], SensorEntity): 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.""" if entity.data == "schedule_mode": return "mdi:calendar-clock" 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.""" if entity.vehicle.details.reports_charging_power_in_watts(): return cast(float, entity.data) / 1000 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.""" data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data) charging_status = data.get_charging_status() if data 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.""" if entity.data == ChargeState.CHARGE_IN_PROGRESS.value: return "mdi:flash" 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.""" data = cast(KamereonVehicleBatteryStatusData, entity.coordinator.data) plug_status = data.get_plug_status() if data 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.""" if entity.data == PlugState.PLUGGED.value: return "mdi:power-plug" 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 round(cast(float, entity.data))