269 lines
8.8 KiB
Python
269 lines
8.8 KiB
Python
"""Support for Renault sensors."""
|
|
from __future__ import annotations
|
|
|
|
from homeassistant.components.sensor import SensorEntity
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (
|
|
DEVICE_CLASS_BATTERY,
|
|
DEVICE_CLASS_ENERGY,
|
|
DEVICE_CLASS_POWER,
|
|
DEVICE_CLASS_TEMPERATURE,
|
|
ENERGY_KILO_WATT_HOUR,
|
|
LENGTH_KILOMETERS,
|
|
PERCENTAGE,
|
|
POWER_KILO_WATT,
|
|
TEMP_CELSIUS,
|
|
TIME_MINUTES,
|
|
VOLUME_LITERS,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
|
|
from .const import (
|
|
DEVICE_CLASS_CHARGE_MODE,
|
|
DEVICE_CLASS_CHARGE_STATE,
|
|
DEVICE_CLASS_PLUG_STATE,
|
|
DOMAIN,
|
|
)
|
|
from .renault_entities import (
|
|
RenaultBatteryDataEntity,
|
|
RenaultChargeModeDataEntity,
|
|
RenaultCockpitDataEntity,
|
|
RenaultDataEntity,
|
|
RenaultHVACDataEntity,
|
|
)
|
|
from .renault_hub import RenaultHub
|
|
from .renault_vehicle import RenaultVehicleProxy
|
|
|
|
ATTR_BATTERY_AVAILABLE_ENERGY = "battery_available_energy"
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
config_entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Set up the Renault entities from config entry."""
|
|
proxy: RenaultHub = hass.data[DOMAIN][config_entry.entry_id]
|
|
entities = get_entities(proxy)
|
|
async_add_entities(entities)
|
|
|
|
|
|
def get_entities(proxy: RenaultHub) -> list[RenaultDataEntity]:
|
|
"""Create Renault entities for all vehicles."""
|
|
entities = []
|
|
for vehicle in proxy.vehicles.values():
|
|
entities.extend(get_vehicle_entities(vehicle))
|
|
return entities
|
|
|
|
|
|
def get_vehicle_entities(vehicle: RenaultVehicleProxy) -> list[RenaultDataEntity]:
|
|
"""Create Renault entities for single vehicle."""
|
|
entities: list[RenaultDataEntity] = []
|
|
if "cockpit" in vehicle.coordinators:
|
|
entities.append(RenaultMileageSensor(vehicle, "Mileage"))
|
|
if vehicle.details.uses_fuel():
|
|
entities.append(RenaultFuelAutonomySensor(vehicle, "Fuel Autonomy"))
|
|
entities.append(RenaultFuelQuantitySensor(vehicle, "Fuel Quantity"))
|
|
if "hvac_status" in vehicle.coordinators:
|
|
entities.append(RenaultOutsideTemperatureSensor(vehicle, "Outside Temperature"))
|
|
if "battery" in vehicle.coordinators:
|
|
entities.append(RenaultBatteryLevelSensor(vehicle, "Battery Level"))
|
|
entities.append(RenaultChargeStateSensor(vehicle, "Charge State"))
|
|
entities.append(
|
|
RenaultChargingRemainingTimeSensor(vehicle, "Charging Remaining Time")
|
|
)
|
|
entities.append(RenaultChargingPowerSensor(vehicle, "Charging Power"))
|
|
entities.append(RenaultPlugStateSensor(vehicle, "Plug State"))
|
|
entities.append(RenaultBatteryAutonomySensor(vehicle, "Battery Autonomy"))
|
|
entities.append(
|
|
RenaultBatteryAvailableEnergySensor(vehicle, "Battery Available Energy")
|
|
)
|
|
entities.append(RenaultBatteryTemperatureSensor(vehicle, "Battery Temperature"))
|
|
if "charge_mode" in vehicle.coordinators:
|
|
entities.append(RenaultChargeModeSensor(vehicle, "Charge Mode"))
|
|
return entities
|
|
|
|
|
|
class RenaultBatteryAutonomySensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Battery autonomy sensor."""
|
|
|
|
_attr_icon = "mdi:ev-station"
|
|
_attr_native_unit_of_measurement = LENGTH_KILOMETERS
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.batteryAutonomy if self.data else None
|
|
|
|
|
|
class RenaultBatteryAvailableEnergySensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Battery available energy sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_ENERGY
|
|
_attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR
|
|
|
|
@property
|
|
def native_value(self) -> float | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.batteryAvailableEnergy if self.data else None
|
|
|
|
|
|
class RenaultBatteryLevelSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Battery Level sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_BATTERY
|
|
_attr_native_unit_of_measurement = PERCENTAGE
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.batteryLevel if self.data else None
|
|
|
|
|
|
class RenaultBatteryTemperatureSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Battery Temperature sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_TEMPERATURE
|
|
_attr_native_unit_of_measurement = TEMP_CELSIUS
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.batteryTemperature if self.data else None
|
|
|
|
|
|
class RenaultChargeModeSensor(RenaultChargeModeDataEntity, SensorEntity):
|
|
"""Charge Mode sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_CHARGE_MODE
|
|
|
|
@property
|
|
def native_value(self) -> str | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.chargeMode if self.data else None
|
|
|
|
@property
|
|
def icon(self) -> str:
|
|
"""Icon handling."""
|
|
if self.data and self.data.chargeMode == "schedule_mode":
|
|
return "mdi:calendar-clock"
|
|
return "mdi:calendar-remove"
|
|
|
|
|
|
class RenaultChargeStateSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Charge State sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_CHARGE_STATE
|
|
|
|
@property
|
|
def native_value(self) -> str | None:
|
|
"""Return the state of this entity."""
|
|
charging_status = self.data.get_charging_status() if self.data else None
|
|
return charging_status.name.lower() if charging_status is not None else None
|
|
|
|
@property
|
|
def icon(self) -> str:
|
|
"""Icon handling."""
|
|
return "mdi:flash" if self.is_charging else "mdi:flash-off"
|
|
|
|
|
|
class RenaultChargingRemainingTimeSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Charging Remaining Time sensor."""
|
|
|
|
_attr_icon = "mdi:timer"
|
|
_attr_native_unit_of_measurement = TIME_MINUTES
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.chargingRemainingTime if self.data else None
|
|
|
|
|
|
class RenaultChargingPowerSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Charging Power sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_POWER
|
|
_attr_native_unit_of_measurement = POWER_KILO_WATT
|
|
|
|
@property
|
|
def native_value(self) -> float | None:
|
|
"""Return the state of this entity."""
|
|
if not self.data or self.data.chargingInstantaneousPower is None:
|
|
return None
|
|
if self.vehicle.details.reports_charging_power_in_watts():
|
|
# Need to convert to kilowatts
|
|
return self.data.chargingInstantaneousPower / 1000
|
|
return self.data.chargingInstantaneousPower
|
|
|
|
|
|
class RenaultFuelAutonomySensor(RenaultCockpitDataEntity, SensorEntity):
|
|
"""Fuel autonomy sensor."""
|
|
|
|
_attr_icon = "mdi:gas-station"
|
|
_attr_native_unit_of_measurement = LENGTH_KILOMETERS
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
if not self.data or self.data.fuelAutonomy is None:
|
|
return None
|
|
return round(self.data.fuelAutonomy)
|
|
|
|
|
|
class RenaultFuelQuantitySensor(RenaultCockpitDataEntity, SensorEntity):
|
|
"""Fuel quantity sensor."""
|
|
|
|
_attr_icon = "mdi:fuel"
|
|
_attr_native_unit_of_measurement = VOLUME_LITERS
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
if not self.data or self.data.fuelQuantity is None:
|
|
return None
|
|
return round(self.data.fuelQuantity)
|
|
|
|
|
|
class RenaultMileageSensor(RenaultCockpitDataEntity, SensorEntity):
|
|
"""Mileage sensor."""
|
|
|
|
_attr_icon = "mdi:sign-direction"
|
|
_attr_native_unit_of_measurement = LENGTH_KILOMETERS
|
|
|
|
@property
|
|
def native_value(self) -> int | None:
|
|
"""Return the state of this entity."""
|
|
if not self.data or self.data.totalMileage is None:
|
|
return None
|
|
return round(self.data.totalMileage)
|
|
|
|
|
|
class RenaultOutsideTemperatureSensor(RenaultHVACDataEntity, SensorEntity):
|
|
"""HVAC Outside Temperature sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_TEMPERATURE
|
|
_attr_native_unit_of_measurement = TEMP_CELSIUS
|
|
|
|
@property
|
|
def native_value(self) -> float | None:
|
|
"""Return the state of this entity."""
|
|
return self.data.externalTemperature if self.data else None
|
|
|
|
|
|
class RenaultPlugStateSensor(RenaultBatteryDataEntity, SensorEntity):
|
|
"""Plug State sensor."""
|
|
|
|
_attr_device_class = DEVICE_CLASS_PLUG_STATE
|
|
|
|
@property
|
|
def native_value(self) -> str | None:
|
|
"""Return the state of this entity."""
|
|
plug_status = self.data.get_plug_status() if self.data else None
|
|
return plug_status.name.lower() if plug_status is not None else None
|
|
|
|
@property
|
|
def icon(self) -> str:
|
|
"""Icon handling."""
|
|
return "mdi:power-plug" if self.is_plugged_in else "mdi:power-plug-off"
|