Files
hassos_config/custom_components/kia_uvo/sensor.py
2023-02-26 11:43:30 +01:00

302 lines
9.5 KiB
Python

"""Sensor for Hyundai / Kia Connect integration."""
from __future__ import annotations
from collections.abc import Callable
import logging
from typing import Final
from hyundai_kia_connect_api import Vehicle
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import (
PERCENTAGE,
TIME_MINUTES,
ENERGY_WATT_HOUR,
ENERGY_KILO_WATT_HOUR,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DOMAIN, DYNAMIC_UNIT
from .coordinator import HyundaiKiaConnectDataUpdateCoordinator
from .entity import HyundaiKiaConnectEntity
_LOGGER = logging.getLogger(__name__)
SENSOR_DESCRIPTIONS: Final[tuple[SensorEntityDescription, ...]] = (
SensorEntityDescription(
key="_total_driving_range",
name="Total Driving Range",
icon="mdi:road-variant",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="_odometer",
name="Odometer",
icon="mdi:speedometer",
native_unit_of_measurement=DYNAMIC_UNIT,
device_class=SensorDeviceClass.DISTANCE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="_last_service_distance",
name="Last Service",
icon="mdi:car-wrench",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="_next_service_distance",
name="Next Service",
icon="mdi:car-wrench",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="car_battery_percentage",
name="Car Battery Level",
icon="mdi:car-battery",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="last_updated_at",
name="Last Updated At",
icon="mdi:update",
device_class=SensorDeviceClass.TIMESTAMP,
),
SensorEntityDescription(
key="ev_battery_percentage",
name="EV Battery Level",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
),
SensorEntityDescription(
key="_ev_driving_range",
name="EV Range",
icon="mdi:road-variant",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="_fuel_driving_range",
name="Fuel Driving Range",
icon="mdi:road-variant",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="fuel_level",
name="Fuel Level",
native_unit_of_measurement=PERCENTAGE,
icon="mdi:fuel",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
key="_air_temperature",
name="Set Temperature",
native_unit_of_measurement=DYNAMIC_UNIT,
device_class=SensorDeviceClass.TEMPERATURE,
),
SensorEntityDescription(
key="ev_estimated_current_charge_duration",
name="Estimated Charge Duration",
icon="mdi:ev-station",
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
key="ev_estimated_fast_charge_duration",
name="Estimated Fast Charge Duration",
icon="mdi:ev-station",
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
key="ev_estimated_portable_charge_duration",
name="Estimated portable Charge Duration",
icon="mdi:ev-station",
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
key="ev_estimated_station_charge_duration",
name="Estimated Station Charge Duration",
icon="mdi:ev-station",
native_unit_of_measurement=TIME_MINUTES,
),
SensorEntityDescription(
key="_ev_target_range_charge_AC",
name="Target Range of Charge AC",
icon="mdi:ev-station",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="_ev_target_range_charge_DC",
name="Target Range of Charge DC",
icon="mdi:ev-station",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=DYNAMIC_UNIT,
),
SensorEntityDescription(
key="total_power_consumed",
name="Monthly Energy Consumption",
icon="mdi:car-electric",
native_unit_of_measurement=ENERGY_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
),
# Need to remove km hard coding. Underlying API needs this fixed first. EU always does KM.
SensorEntityDescription(
key="power_consumption_30d",
name="Average Energy Consumption",
icon="mdi:car-electric",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=f"{ENERGY_WATT_HOUR}/km",
),
SensorEntityDescription(
key="front_left_seat_status",
name="Front Left Seat",
icon="mdi:car-seat-heater",
),
SensorEntityDescription(
key="front_right_seat_status",
name="Front Right Seat",
icon="mdi:car-seat-heater",
),
SensorEntityDescription(
key="rear_left_seat_status",
name="Rear Left Seat",
icon="mdi:car-seat-heater",
),
SensorEntityDescription(
key="rear_right_seat_status",
name="Rear Right Seat",
icon="mdi:car-seat-heater",
),
SensorEntityDescription(
key="_geocode_name",
name="Geocoded Location",
icon="mdi:map",
),
SensorEntityDescription(
key="dtc_count",
name="DTC Count",
icon="mdi:alert-circle",
),
SensorEntityDescription(
key="ev_first_departure_time",
name="EV First Scheduled Depature Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_second_departure_time",
name="EV Second Scheduled Depature Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_off_peak_start_time",
name="EV Off Peak Start Time",
icon="mdi:clock-outline",
),
SensorEntityDescription(
key="ev_off_peak_end_time",
name="EV Off Peak End Time",
icon="mdi:clock-outline",
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up sensor platform."""
coordinator = hass.data[DOMAIN][config_entry.unique_id]
entities = []
for vehicle_id in coordinator.vehicle_manager.vehicles.keys():
vehicle: Vehicle = coordinator.vehicle_manager.vehicles[vehicle_id]
for description in SENSOR_DESCRIPTIONS:
if getattr(vehicle, description.key, None) is not None:
entities.append(
HyundaiKiaConnectSensor(coordinator, description, vehicle)
)
async_add_entities(entities)
async_add_entities(
[VehicleEntity(coordinator, coordinator.vehicle_manager.vehicles[vehicle_id])],
True,
)
return True
class HyundaiKiaConnectSensor(SensorEntity, HyundaiKiaConnectEntity):
"""Hyundai / Kia Connect sensor class."""
def __init__(
self, coordinator, description: SensorEntityDescription, vehicle: Vehicle
):
"""Initialize the sensor."""
super().__init__(coordinator, vehicle)
self._description = description
self._key = self._description.key
self._attr_unique_id = f"{DOMAIN}_{vehicle.id}_{self._key}"
self._attr_icon = self._description.icon
self._attr_name = f"{vehicle.name} {self._description.name}"
self._attr_state_class = self._description.state_class
self._attr_device_class = self._description.device_class
@property
def native_value(self):
"""Return the value reported by the sensor."""
return getattr(self.vehicle, self._key)
@property
def native_unit_of_measurement(self):
"""Return the unit the value was reported in by the sensor"""
if self._description.native_unit_of_measurement == DYNAMIC_UNIT:
return getattr(self.vehicle, self._key + "_unit")
else:
return self._description.native_unit_of_measurement
@property
def state_attributes(self):
if self._description.key == "_geocode_name":
return {"address": getattr(self.vehicle, "_geocode_address")}
elif self._description.key == "dtc_count":
return {"DTC Text": getattr(self.vehicle, "dtc_descriptions")}
class VehicleEntity(SensorEntity, HyundaiKiaConnectEntity):
def __init__(self, coordinator, vehicle: Vehicle):
super().__init__(coordinator, vehicle)
@property
def state(self):
return "on"
@property
def is_on(self) -> bool:
return True
@property
def state_attributes(self):
return {
"vehicle_data": self.vehicle.data,
"vehicle_name": self.vehicle.name,
}
@property
def name(self):
return f"{self.vehicle.name} Data"
@property
def unique_id(self):
return f"{DOMAIN}-all-data-{self.vehicle.id}"