"""Battery Charge and Range Support for the Nissan Leaf.""" import logging from typing import override from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.const import PERCENTAGE, UnitOfLength from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.icon import icon_for_battery_level from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType, StateType from homeassistant.util.unit_conversion import DistanceConverter from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM from . import LeafDataStore from .const import ( DATA_BATTERY, DATA_CHARGING, DATA_LEAF, DATA_RANGE_AC, DATA_RANGE_AC_OFF, ) from .entity import LeafEntity _LOGGER = logging.getLogger(__name__) def setup_platform( hass: HomeAssistant, config: ConfigType, add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Sensors setup.""" if discovery_info is None: return entities: list[LeafEntity] = [] for vin, datastore in hass.data[DATA_LEAF].items(): _LOGGER.debug("Adding sensors for vin=%s", vin) entities.append(LeafBatterySensor(datastore)) entities.append(LeafRangeSensor(datastore, True)) entities.append(LeafRangeSensor(datastore, False)) add_entities(entities, True) class LeafBatterySensor(LeafEntity, SensorEntity): """Nissan Leaf Battery Sensor.""" _attr_device_class = SensorDeviceClass.BATTERY _attr_native_unit_of_measurement = PERCENTAGE def __init__(self, car: LeafDataStore) -> None: """Set up battery sensor.""" super().__init__(car) self._attr_unique_id = f"{self.car.leaf.vin.lower()}_soc" @property @override def name(self) -> str: """Sensor Name.""" return f"{self.car.leaf.nickname} Charge" @property @override def native_value(self) -> StateType: """Battery state percentage.""" if self.car.data[DATA_BATTERY] is None: return None return round(self.car.data[DATA_BATTERY]) # type: ignore[no-any-return] @property @override def icon(self) -> str: """Battery state icon handling.""" chargestate = self.car.data[DATA_CHARGING] return icon_for_battery_level(battery_level=self.state, charging=chargestate) class LeafRangeSensor(LeafEntity, SensorEntity): """Nissan Leaf Range Sensor.""" _attr_icon = "mdi:speedometer" def __init__(self, car: LeafDataStore, ac_on: bool) -> None: """Set up range sensor. Store if AC on.""" self._ac_on = ac_on super().__init__(car) if ac_on: self._attr_unique_id = f"{self.car.leaf.vin.lower()}_range_ac" else: self._attr_unique_id = f"{self.car.leaf.vin.lower()}_range" @property @override def name(self) -> str: """Update sensor name depending on AC.""" if self._ac_on is True: return f"{self.car.leaf.nickname} Range (AC)" return f"{self.car.leaf.nickname} Range" @override def log_registration(self) -> None: """Log registration.""" _LOGGER.debug( "Registered LeafRangeSensor integration with Home Assistant for VIN %s", self.car.leaf.vin, ) @property @override def native_value(self) -> float | None: """Battery range in miles or kms.""" ret: float | None if self._ac_on: ret = self.car.data[DATA_RANGE_AC] else: ret = self.car.data[DATA_RANGE_AC_OFF] if ret is None: return None if self.car.hass.config.units is US_CUSTOMARY_SYSTEM or self.car.force_miles: ret = DistanceConverter.convert( ret, UnitOfLength.KILOMETERS, UnitOfLength.MILES ) return round(ret) @property @override def native_unit_of_measurement(self) -> str: """Battery range unit.""" if self.car.hass.config.units is US_CUSTOMARY_SYSTEM or self.car.force_miles: return UnitOfLength.MILES return UnitOfLength.KILOMETERS