<commit_before>"""Support for reading vehicle status from MyBMW portal."""
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
import logging
from typing import cast

from bimmer_connected.models import ValueWithUnit
from bimmer_connected.vehicle import MyBMWVehicle

from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
    LENGTH_KILOMETERS,
    LENGTH_MILES,
    PERCENTAGE,
    VOLUME_GALLONS,
    VOLUME_LITERS,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util.unit_system import UnitSystem

from . import BMWBaseEntity
from .const import DOMAIN, UNIT_MAP
from .coordinator import BMWDataUpdateCoordinator

_LOGGER = logging.getLogger(__name__)


@dataclass
class BMWSensorEntityDescription(SensorEntityDescription):
    """Describes BMW sensor entity."""

    key_class: str | None = None
    unit_metric: str | None = None
    unit_imperial: str | None = None
    value: Callable = lambda x, y: x


def convert_and_round(
    state: ValueWithUnit,
    converter: Callable[[float | None, str], float],
    precision: int,
) -> float | None:
    """Safely convert and round a value from ValueWithUnit."""
    if state.value and state.unit:
        return round(
            converter(state.value, UNIT_MAP.get(state.unit, state.unit)), precision
        )
    if state.value:
        return state.value
    return None


SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
    # --- Generic ---
    "charging_start_time": BMWSensorEntityDescription(
        key="charging_start_time",
        key_class="fuel_and_battery",
        device_class=SensorDeviceClass.TIMESTAMP,
        entity_registry_enabled_default=False,
    ),
    "charging_end_time": BMWSensorEntityDescription(
        key="charging_end_time",
        key_class="fuel_and_battery",
        device_class=SensorDeviceClass.TIMESTAMP,
    ),
    "charging_time_label": BMWSensorEntityDescription(
        key="charging_time_label",
        key_class="fuel_and_battery",
        entity_registry_enabled_default=False,
    ),
    "charging_status": BMWSensorEntityDescription(
        key="charging_status",
        key_class="fuel_and_battery",
        icon="mdi:ev-station",
        value=lambda x, y: x.value,
    ),
    "remaining_battery_percent": BMWSensorEntityDescription(
        key="remaining_battery_percent",
        key_class="fuel_and_battery",
        unit_metric=PERCENTAGE,
        unit_imperial=PERCENTAGE,
        device_class=SensorDeviceClass.BATTERY,
    ),
    # --- Specific ---
    "mileage": BMWSensorEntityDescription(
        key="mileage",<commit_msg>Remove `charging_time_label` sensor in BMW Connected Drive (#76616)<commit_after>"""Support for reading vehicle status from MyBMW portal."""
from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass
import logging
from typing import cast

from bimmer_connected.models import ValueWithUnit
from bimmer_connected.vehicle import MyBMWVehicle

from homeassistant.components.sensor import (
    SensorDeviceClass,
    SensorEntity,
    SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
    LENGTH_KILOMETERS,
    LENGTH_MILES,
    PERCENTAGE,
    VOLUME_GALLONS,
    VOLUME_LITERS,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util.unit_system import UnitSystem

from . import BMWBaseEntity
from .const import DOMAIN, UNIT_MAP
from .coordinator import BMWDataUpdateCoordinator

_LOGGER = logging.getLogger(__name__)


@dataclass
class BMWSensorEntityDescription(SensorEntityDescription):
    """Describes BMW sensor entity."""

    key_class: str | None = None
    unit_metric: str | None = None
    unit_imperial: str | None = None
    value: Callable = lambda x, y: x


def convert_and_round(
    state: ValueWithUnit,
    converter: Callable[[float | None, str], float],
    precision: int,
) -> float | None:
    """Safely convert and round a value from ValueWithUnit."""
    if state.value and state.unit:
        return round(
            converter(state.value, UNIT_MAP.get(state.unit, state.unit)), precision
        )
    if state.value:
        return state.value
    return None


SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
    # --- Generic ---
    "charging_start_time": BMWSensorEntityDescription(
        key="charging_start_time",
        key_class="fuel_and_battery",
        device_class=SensorDeviceClass.TIMESTAMP,
        entity_registry_enabled_default=False,
    ),
    "charging_end_time": BMWSensorEntityDescription(
        key="charging_end_time",
        key_class="fuel_and_battery",
        device_class=SensorDeviceClass.TIMESTAMP,
    ),
    "charging_status": BMWSensorEntityDescription(
        key="charging_status",
        key_class="fuel_and_battery",
        icon="mdi:ev-station",
        value=lambda x, y: x.value,
    ),
    "remaining_battery_percent": BMWSensorEntityDescription(
        key="remaining_battery_percent",
        key_class="fuel_and_battery",
        unit_metric=PERCENTAGE,
        unit_imperial=PERCENTAGE,
        device_class=SensorDeviceClass.BATTERY,
    ),
    # --- Specific ---
    "mileage": BMWSensorEntityDescription(
        key="mileage",
{'fraction_non_alphanumeric': 0.08228070175438597, 'fraction_numerical': 0.0008771929824561404, 'mean_word_length': 3.856047700170358, 'pattern_counts': {'":': 11, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1367141', 'n_tokens_mistral': 1728, 'n_tokens_neox': 1697, 'n_words': 371}