mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Use EntityDescription - bmw_connected_drive sensor (#57796)
This commit is contained in:
parent
4fd8b27ce6
commit
6ca23c67ff
@ -1,12 +1,16 @@
|
|||||||
"""Support for reading vehicle status from BMW connected drive portal."""
|
"""Support for reading vehicle status from BMW connected drive portal."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from copy import copy
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from bimmer_connected.const import SERVICE_ALL_TRIPS, SERVICE_LAST_TRIP, SERVICE_STATUS
|
from bimmer_connected.const import SERVICE_ALL_TRIPS, SERVICE_LAST_TRIP, SERVICE_STATUS
|
||||||
from bimmer_connected.state import ChargingState
|
from bimmer_connected.state import ChargingState
|
||||||
|
from bimmer_connected.vehicle import ConnectedDriveVehicle
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import SensorEntity, SensorEntityDescription
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_UNIT_SYSTEM_IMPERIAL,
|
CONF_UNIT_SYSTEM_IMPERIAL,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
@ -21,390 +25,399 @@ from homeassistant.const import (
|
|||||||
VOLUME_GALLONS,
|
VOLUME_GALLONS,
|
||||||
VOLUME_LITERS,
|
VOLUME_LITERS,
|
||||||
)
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.icon import icon_for_battery_level
|
from homeassistant.helpers.icon import icon_for_battery_level
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
from homeassistant.util.unit_system import UnitSystem
|
||||||
|
|
||||||
from . import DOMAIN as BMW_DOMAIN, BMWConnectedDriveBaseEntity
|
from . import (
|
||||||
|
DOMAIN as BMW_DOMAIN,
|
||||||
|
BMWConnectedDriveAccount,
|
||||||
|
BMWConnectedDriveBaseEntity,
|
||||||
|
)
|
||||||
from .const import CONF_ACCOUNT, DATA_ENTRIES
|
from .const import CONF_ACCOUNT, DATA_ENTRIES
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SENSOR_TYPES: dict[str, tuple[str | None, str | None, str | None, str | None, bool]] = {
|
|
||||||
# "<ID>": (<MDI_ICON>, <DEVICE_CLASS>, <UNIT_OF_MEASUREMENT (metric)>, <UNIT_OF_MEASUREMENT (imperial)>, <ENABLED_BY_DEFAULT>),
|
@dataclass
|
||||||
|
class BMWSensorEntityDescription(SensorEntityDescription):
|
||||||
|
"""Describes BMW sensor entity."""
|
||||||
|
|
||||||
|
unit_metric: str | None = None
|
||||||
|
unit_imperial: str | None = None
|
||||||
|
|
||||||
|
|
||||||
|
SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
|
||||||
# --- Generic ---
|
# --- Generic ---
|
||||||
"charging_time_remaining": (
|
"charging_time_remaining": BMWSensorEntityDescription(
|
||||||
"mdi:update",
|
key="charging_time_remaining",
|
||||||
None,
|
icon="mdi:update",
|
||||||
TIME_HOURS,
|
unit_metric=TIME_HOURS,
|
||||||
TIME_HOURS,
|
unit_imperial=TIME_HOURS,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"charging_status": (
|
"charging_status": BMWSensorEntityDescription(
|
||||||
"mdi:battery-charging",
|
key="charging_status",
|
||||||
None,
|
icon="mdi:battery-charging",
|
||||||
None,
|
|
||||||
None,
|
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
# No icon as this is dealt with directly as a special case in icon()
|
# No icon as this is dealt with directly as a special case in icon()
|
||||||
"charging_level_hv": (
|
"charging_level_hv": BMWSensorEntityDescription(
|
||||||
None,
|
key="charging_level_hv",
|
||||||
None,
|
unit_metric=PERCENTAGE,
|
||||||
PERCENTAGE,
|
unit_imperial=PERCENTAGE,
|
||||||
PERCENTAGE,
|
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
# LastTrip attributes
|
# LastTrip attributes
|
||||||
"date_utc": (
|
"date_utc": BMWSensorEntityDescription(
|
||||||
None,
|
key="date_utc",
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
device_class=DEVICE_CLASS_TIMESTAMP,
|
||||||
None,
|
|
||||||
None,
|
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"duration": (
|
"duration": BMWSensorEntityDescription(
|
||||||
"mdi:timer-outline",
|
key="duration",
|
||||||
None,
|
icon="mdi:timer-outline",
|
||||||
TIME_MINUTES,
|
unit_metric=TIME_MINUTES,
|
||||||
TIME_MINUTES,
|
unit_imperial=TIME_MINUTES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"electric_distance_ratio": (
|
"electric_distance_ratio": BMWSensorEntityDescription(
|
||||||
"mdi:percent-outline",
|
key="electric_distance_ratio",
|
||||||
None,
|
icon="mdi:percent-outline",
|
||||||
PERCENTAGE,
|
unit_metric=PERCENTAGE,
|
||||||
PERCENTAGE,
|
unit_imperial=PERCENTAGE,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
# AllTrips attributes
|
# AllTrips attributes
|
||||||
"battery_size_max": (
|
"battery_size_max": BMWSensorEntityDescription(
|
||||||
"mdi:battery-charging-high",
|
key="battery_size_max",
|
||||||
None,
|
icon="mdi:battery-charging-high",
|
||||||
ENERGY_WATT_HOUR,
|
unit_metric=ENERGY_WATT_HOUR,
|
||||||
ENERGY_WATT_HOUR,
|
unit_imperial=ENERGY_WATT_HOUR,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"reset_date_utc": (
|
"reset_date_utc": BMWSensorEntityDescription(
|
||||||
None,
|
key="reset_date_utc",
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
device_class=DEVICE_CLASS_TIMESTAMP,
|
||||||
None,
|
entity_registry_enabled_default=False,
|
||||||
None,
|
|
||||||
False,
|
|
||||||
),
|
),
|
||||||
"saved_co2": (
|
"saved_co2": BMWSensorEntityDescription(
|
||||||
"mdi:tree-outline",
|
key="saved_co2",
|
||||||
None,
|
icon="mdi:tree-outline",
|
||||||
MASS_KILOGRAMS,
|
unit_metric=MASS_KILOGRAMS,
|
||||||
MASS_KILOGRAMS,
|
unit_imperial=MASS_KILOGRAMS,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"saved_co2_green_energy": (
|
"saved_co2_green_energy": BMWSensorEntityDescription(
|
||||||
"mdi:tree-outline",
|
key="saved_co2_green_energy",
|
||||||
None,
|
icon="mdi:tree-outline",
|
||||||
MASS_KILOGRAMS,
|
unit_metric=MASS_KILOGRAMS,
|
||||||
MASS_KILOGRAMS,
|
unit_imperial=MASS_KILOGRAMS,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
# --- Specific ---
|
# --- Specific ---
|
||||||
"mileage": (
|
"mileage": BMWSensorEntityDescription(
|
||||||
"mdi:speedometer",
|
key="mileage",
|
||||||
None,
|
icon="mdi:speedometer",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"remaining_range_total": (
|
"remaining_range_total": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="remaining_range_total",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"remaining_range_electric": (
|
"remaining_range_electric": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="remaining_range_electric",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"remaining_range_fuel": (
|
"remaining_range_fuel": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="remaining_range_fuel",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"max_range_electric": (
|
"max_range_electric": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="max_range_electric",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"remaining_fuel": (
|
"remaining_fuel": BMWSensorEntityDescription(
|
||||||
"mdi:gas-station",
|
key="remaining_fuel",
|
||||||
None,
|
icon="mdi:gas-station",
|
||||||
VOLUME_LITERS,
|
unit_metric=VOLUME_LITERS,
|
||||||
VOLUME_GALLONS,
|
unit_imperial=VOLUME_GALLONS,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
# LastTrip attributes
|
# LastTrip attributes
|
||||||
"average_combined_consumption": (
|
"average_combined_consumption": BMWSensorEntityDescription(
|
||||||
"mdi:flash",
|
key="average_combined_consumption",
|
||||||
None,
|
icon="mdi:flash",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"average_electric_consumption": (
|
"average_electric_consumption": BMWSensorEntityDescription(
|
||||||
"mdi:power-plug-outline",
|
key="average_electric_consumption",
|
||||||
None,
|
icon="mdi:power-plug-outline",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"average_recuperation": (
|
"average_recuperation": BMWSensorEntityDescription(
|
||||||
"mdi:recycle-variant",
|
key="average_recuperation",
|
||||||
None,
|
icon="mdi:recycle-variant",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"electric_distance": (
|
"electric_distance": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="electric_distance",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"saved_fuel": (
|
"saved_fuel": BMWSensorEntityDescription(
|
||||||
"mdi:fuel",
|
key="saved_fuel",
|
||||||
None,
|
icon="mdi:fuel",
|
||||||
VOLUME_LITERS,
|
unit_metric=VOLUME_LITERS,
|
||||||
VOLUME_GALLONS,
|
unit_imperial=VOLUME_GALLONS,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_distance": (
|
"total_distance": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_distance",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
# AllTrips attributes
|
# AllTrips attributes
|
||||||
"average_combined_consumption_community_average": (
|
"average_combined_consumption_community_average": BMWSensorEntityDescription(
|
||||||
"mdi:flash",
|
key="average_combined_consumption_community_average",
|
||||||
None,
|
icon="mdi:flash",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_combined_consumption_community_high": (
|
"average_combined_consumption_community_high": BMWSensorEntityDescription(
|
||||||
"mdi:flash",
|
key="average_combined_consumption_community_high",
|
||||||
None,
|
icon="mdi:flash",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_combined_consumption_community_low": (
|
"average_combined_consumption_community_low": BMWSensorEntityDescription(
|
||||||
"mdi:flash",
|
key="average_combined_consumption_community_low",
|
||||||
None,
|
icon="mdi:flash",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_combined_consumption_user_average": (
|
"average_combined_consumption_user_average": BMWSensorEntityDescription(
|
||||||
"mdi:flash",
|
key="average_combined_consumption_user_average",
|
||||||
None,
|
icon="mdi:flash",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"average_electric_consumption_community_average": (
|
"average_electric_consumption_community_average": BMWSensorEntityDescription(
|
||||||
"mdi:power-plug-outline",
|
key="average_electric_consumption_community_average",
|
||||||
None,
|
icon="mdi:power-plug-outline",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_electric_consumption_community_high": (
|
"average_electric_consumption_community_high": BMWSensorEntityDescription(
|
||||||
"mdi:power-plug-outline",
|
key="average_electric_consumption_community_high",
|
||||||
None,
|
icon="mdi:power-plug-outline",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_electric_consumption_community_low": (
|
"average_electric_consumption_community_low": BMWSensorEntityDescription(
|
||||||
"mdi:power-plug-outline",
|
key="average_electric_consumption_community_low",
|
||||||
None,
|
icon="mdi:power-plug-outline",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_electric_consumption_user_average": (
|
"average_electric_consumption_user_average": BMWSensorEntityDescription(
|
||||||
"mdi:power-plug-outline",
|
key="average_electric_consumption_user_average",
|
||||||
None,
|
icon="mdi:power-plug-outline",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"average_recuperation_community_average": (
|
"average_recuperation_community_average": BMWSensorEntityDescription(
|
||||||
"mdi:recycle-variant",
|
key="average_recuperation_community_average",
|
||||||
None,
|
icon="mdi:recycle-variant",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_recuperation_community_high": (
|
"average_recuperation_community_high": BMWSensorEntityDescription(
|
||||||
"mdi:recycle-variant",
|
key="average_recuperation_community_high",
|
||||||
None,
|
icon="mdi:recycle-variant",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_recuperation_community_low": (
|
"average_recuperation_community_low": BMWSensorEntityDescription(
|
||||||
"mdi:recycle-variant",
|
key="average_recuperation_community_low",
|
||||||
None,
|
icon="mdi:recycle-variant",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"average_recuperation_user_average": (
|
"average_recuperation_user_average": BMWSensorEntityDescription(
|
||||||
"mdi:recycle-variant",
|
key="average_recuperation_user_average",
|
||||||
None,
|
icon="mdi:recycle-variant",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
unit_metric=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
unit_imperial=f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"chargecycle_range_community_average": (
|
"chargecycle_range_community_average": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_community_average",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"chargecycle_range_community_high": (
|
"chargecycle_range_community_high": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_community_high",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"chargecycle_range_community_low": (
|
"chargecycle_range_community_low": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_community_low",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"chargecycle_range_user_average": (
|
"chargecycle_range_user_average": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_user_average",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"chargecycle_range_user_current_charge_cycle": (
|
"chargecycle_range_user_current_charge_cycle": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_user_current_charge_cycle",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"chargecycle_range_user_high": (
|
"chargecycle_range_user_high": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="chargecycle_range_user_high",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
True,
|
|
||||||
),
|
),
|
||||||
"total_electric_distance_community_average": (
|
"total_electric_distance_community_average": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_electric_distance_community_average",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_electric_distance_community_high": (
|
"total_electric_distance_community_high": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_electric_distance_community_high",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_electric_distance_community_low": (
|
"total_electric_distance_community_low": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_electric_distance_community_low",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_electric_distance_user_average": (
|
"total_electric_distance_user_average": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_electric_distance_user_average",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_electric_distance_user_total": (
|
"total_electric_distance_user_total": BMWSensorEntityDescription(
|
||||||
"mdi:map-marker-distance",
|
key="total_electric_distance_user_total",
|
||||||
None,
|
icon="mdi:map-marker-distance",
|
||||||
LENGTH_KILOMETERS,
|
unit_metric=LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
unit_imperial=LENGTH_MILES,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_saved_fuel": (
|
"total_saved_fuel": BMWSensorEntityDescription(
|
||||||
"mdi:fuel",
|
key="total_saved_fuel",
|
||||||
None,
|
icon="mdi:fuel",
|
||||||
VOLUME_LITERS,
|
unit_metric=VOLUME_LITERS,
|
||||||
VOLUME_GALLONS,
|
unit_imperial=VOLUME_GALLONS,
|
||||||
False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
DEFAULT_BMW_DESCRIPTION = BMWSensorEntityDescription(
|
||||||
|
key="",
|
||||||
|
entity_registry_enabled_default=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
"""Set up the BMW ConnectedDrive sensors from config entry."""
|
"""Set up the BMW ConnectedDrive sensors from config entry."""
|
||||||
# pylint: disable=too-many-nested-blocks
|
# pylint: disable=too-many-nested-blocks
|
||||||
account = hass.data[BMW_DOMAIN][DATA_ENTRIES][config_entry.entry_id][CONF_ACCOUNT]
|
unit_system = hass.config.units
|
||||||
entities = []
|
account: BMWConnectedDriveAccount = hass.data[BMW_DOMAIN][DATA_ENTRIES][
|
||||||
|
config_entry.entry_id
|
||||||
|
][CONF_ACCOUNT]
|
||||||
|
entities: list[BMWConnectedDriveSensor] = []
|
||||||
|
|
||||||
for vehicle in account.account.vehicles:
|
for vehicle in account.account.vehicles:
|
||||||
for service in vehicle.available_state_services:
|
for service in vehicle.available_state_services:
|
||||||
if service == SERVICE_STATUS:
|
if service == SERVICE_STATUS:
|
||||||
for attribute_name in vehicle.drive_train_attributes:
|
entities.extend(
|
||||||
if attribute_name in vehicle.available_attributes:
|
[
|
||||||
device = BMWConnectedDriveSensor(
|
BMWConnectedDriveSensor(
|
||||||
hass, account, vehicle, attribute_name
|
account, vehicle, description, unit_system
|
||||||
)
|
)
|
||||||
entities.append(device)
|
for attribute_name in vehicle.drive_train_attributes
|
||||||
|
if attribute_name in vehicle.available_attributes
|
||||||
|
and (description := SENSOR_TYPES.get(attribute_name))
|
||||||
|
]
|
||||||
|
)
|
||||||
if service == SERVICE_LAST_TRIP:
|
if service == SERVICE_LAST_TRIP:
|
||||||
for attribute_name in vehicle.state.last_trip.available_attributes:
|
entities.extend(
|
||||||
if attribute_name == "date":
|
[
|
||||||
device = BMWConnectedDriveSensor(
|
BMWConnectedDriveSensor(
|
||||||
hass,
|
account, vehicle, description, unit_system, service
|
||||||
|
)
|
||||||
|
for attribute_name in vehicle.state.last_trip.available_attributes
|
||||||
|
if attribute_name != "date"
|
||||||
|
and (description := SENSOR_TYPES.get(attribute_name))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if "date" in vehicle.state.last_trip.available_attributes:
|
||||||
|
entities.append(
|
||||||
|
BMWConnectedDriveSensor(
|
||||||
account,
|
account,
|
||||||
vehicle,
|
vehicle,
|
||||||
"date_utc",
|
SENSOR_TYPES["date_utc"],
|
||||||
|
unit_system,
|
||||||
service,
|
service,
|
||||||
)
|
)
|
||||||
entities.append(device)
|
)
|
||||||
else:
|
|
||||||
device = BMWConnectedDriveSensor(
|
|
||||||
hass, account, vehicle, attribute_name, service
|
|
||||||
)
|
|
||||||
entities.append(device)
|
|
||||||
if service == SERVICE_ALL_TRIPS:
|
if service == SERVICE_ALL_TRIPS:
|
||||||
for attribute_name in vehicle.state.all_trips.available_attributes:
|
for attribute_name in vehicle.state.all_trips.available_attributes:
|
||||||
if attribute_name == "reset_date":
|
if attribute_name == "reset_date":
|
||||||
device = BMWConnectedDriveSensor(
|
entities.append(
|
||||||
hass,
|
BMWConnectedDriveSensor(
|
||||||
account,
|
account,
|
||||||
vehicle,
|
vehicle,
|
||||||
"reset_date_utc",
|
SENSOR_TYPES["reset_date_utc"],
|
||||||
service,
|
unit_system,
|
||||||
|
service,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
entities.append(device)
|
|
||||||
elif attribute_name in (
|
elif attribute_name in (
|
||||||
"average_combined_consumption",
|
"average_combined_consumption",
|
||||||
"average_electric_consumption",
|
"average_electric_consumption",
|
||||||
@ -412,45 +425,60 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
"chargecycle_range",
|
"chargecycle_range",
|
||||||
"total_electric_distance",
|
"total_electric_distance",
|
||||||
):
|
):
|
||||||
for attr in (
|
entities.extend(
|
||||||
"community_average",
|
[
|
||||||
"community_high",
|
BMWConnectedDriveSensor(
|
||||||
"community_low",
|
account,
|
||||||
"user_average",
|
vehicle,
|
||||||
):
|
SENSOR_TYPES[f"{attribute_name}_{attr}"],
|
||||||
device = BMWConnectedDriveSensor(
|
unit_system,
|
||||||
hass,
|
service,
|
||||||
|
)
|
||||||
|
for attr in (
|
||||||
|
"community_average",
|
||||||
|
"community_high",
|
||||||
|
"community_low",
|
||||||
|
"user_average",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if attribute_name == "chargecycle_range":
|
||||||
|
entities.extend(
|
||||||
|
BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
SENSOR_TYPES[f"{attribute_name}_{attr}"],
|
||||||
|
unit_system,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
for attr in ("user_current_charge_cycle", "user_high")
|
||||||
|
)
|
||||||
|
elif attribute_name == "total_electric_distance":
|
||||||
|
entities.extend(
|
||||||
|
[
|
||||||
|
BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
SENSOR_TYPES[f"{attribute_name}_{attr}"],
|
||||||
|
unit_system,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
for attr in ("user_total",)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if (description := SENSOR_TYPES.get(attribute_name)) is None:
|
||||||
|
description = copy(DEFAULT_BMW_DESCRIPTION)
|
||||||
|
description.key = attribute_name
|
||||||
|
entities.append(
|
||||||
|
BMWConnectedDriveSensor(
|
||||||
account,
|
account,
|
||||||
vehicle,
|
vehicle,
|
||||||
f"{attribute_name}_{attr}",
|
description,
|
||||||
|
unit_system,
|
||||||
service,
|
service,
|
||||||
)
|
)
|
||||||
entities.append(device)
|
|
||||||
if attribute_name == "chargecycle_range":
|
|
||||||
for attr in ("user_current_charge_cycle", "user_high"):
|
|
||||||
device = BMWConnectedDriveSensor(
|
|
||||||
hass,
|
|
||||||
account,
|
|
||||||
vehicle,
|
|
||||||
f"{attribute_name}_{attr}",
|
|
||||||
service,
|
|
||||||
)
|
|
||||||
entities.append(device)
|
|
||||||
if attribute_name == "total_electric_distance":
|
|
||||||
for attr in ("user_total",):
|
|
||||||
device = BMWConnectedDriveSensor(
|
|
||||||
hass,
|
|
||||||
account,
|
|
||||||
vehicle,
|
|
||||||
f"{attribute_name}_{attr}",
|
|
||||||
service,
|
|
||||||
)
|
|
||||||
entities.append(device)
|
|
||||||
else:
|
|
||||||
device = BMWConnectedDriveSensor(
|
|
||||||
hass, account, vehicle, attribute_name, service
|
|
||||||
)
|
)
|
||||||
entities.append(device)
|
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
@ -458,52 +486,57 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
||||||
"""Representation of a BMW vehicle sensor."""
|
"""Representation of a BMW vehicle sensor."""
|
||||||
|
|
||||||
def __init__(self, hass, account, vehicle, attribute: str, service=None):
|
entity_description: BMWSensorEntityDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
account: BMWConnectedDriveAccount,
|
||||||
|
vehicle: ConnectedDriveVehicle,
|
||||||
|
description: BMWSensorEntityDescription,
|
||||||
|
unit_system: UnitSystem,
|
||||||
|
service: str | None = None,
|
||||||
|
) -> None:
|
||||||
"""Initialize BMW vehicle sensor."""
|
"""Initialize BMW vehicle sensor."""
|
||||||
super().__init__(account, vehicle)
|
super().__init__(account, vehicle)
|
||||||
|
self.entity_description = description
|
||||||
|
|
||||||
self._attribute = attribute
|
|
||||||
self._service = service
|
self._service = service
|
||||||
if service:
|
if service:
|
||||||
self._attr_name = f"{vehicle.name} {service.lower()}_{attribute}"
|
self._attr_name = f"{vehicle.name} {service.lower()}_{description.key}"
|
||||||
self._attr_unique_id = f"{vehicle.vin}-{service.lower()}-{attribute}"
|
self._attr_unique_id = f"{vehicle.vin}-{service.lower()}-{description.key}"
|
||||||
else:
|
else:
|
||||||
self._attr_name = f"{vehicle.name} {attribute}"
|
self._attr_name = f"{vehicle.name} {description.key}"
|
||||||
self._attr_unique_id = f"{vehicle.vin}-{attribute}"
|
self._attr_unique_id = f"{vehicle.vin}-{description.key}"
|
||||||
self._attribute_info = SENSOR_TYPES.get(
|
|
||||||
attribute, (None, None, None, None, True)
|
if unit_system.name == CONF_UNIT_SYSTEM_IMPERIAL:
|
||||||
)
|
self._attr_native_unit_of_measurement = description.unit_imperial
|
||||||
self._attr_entity_registry_enabled_default = self._attribute_info[4]
|
|
||||||
self._attr_icon = self._attribute_info[0]
|
|
||||||
self._attr_device_class = self._attribute_info[1]
|
|
||||||
if hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL:
|
|
||||||
self._attr_native_unit_of_measurement = self._attribute_info[3]
|
|
||||||
else:
|
else:
|
||||||
self._attr_native_unit_of_measurement = self._attribute_info[2]
|
self._attr_native_unit_of_measurement = description.unit_metric
|
||||||
|
|
||||||
def update(self) -> None:
|
def update(self) -> None:
|
||||||
"""Read new state data from the library."""
|
"""Read new state data from the library."""
|
||||||
_LOGGER.debug("Updating %s", self._vehicle.name)
|
_LOGGER.debug("Updating %s", self._vehicle.name)
|
||||||
vehicle_state = self._vehicle.state
|
vehicle_state = self._vehicle.state
|
||||||
if self._attribute == "charging_status":
|
sensor_key = self.entity_description.key
|
||||||
self._attr_native_value = getattr(vehicle_state, self._attribute).value
|
if sensor_key == "charging_status":
|
||||||
|
self._attr_native_value = getattr(vehicle_state, sensor_key).value
|
||||||
elif self.unit_of_measurement == VOLUME_GALLONS:
|
elif self.unit_of_measurement == VOLUME_GALLONS:
|
||||||
value = getattr(vehicle_state, self._attribute)
|
value = getattr(vehicle_state, sensor_key)
|
||||||
value_converted = self.hass.config.units.volume(value, VOLUME_LITERS)
|
value_converted = self.hass.config.units.volume(value, VOLUME_LITERS)
|
||||||
self._attr_native_value = round(value_converted)
|
self._attr_native_value = round(value_converted)
|
||||||
elif self.unit_of_measurement == LENGTH_MILES:
|
elif self.unit_of_measurement == LENGTH_MILES:
|
||||||
value = getattr(vehicle_state, self._attribute)
|
value = getattr(vehicle_state, sensor_key)
|
||||||
value_converted = self.hass.config.units.length(value, LENGTH_KILOMETERS)
|
value_converted = self.hass.config.units.length(value, LENGTH_KILOMETERS)
|
||||||
self._attr_native_value = round(value_converted)
|
self._attr_native_value = round(value_converted)
|
||||||
elif self._service is None:
|
elif self._service is None:
|
||||||
self._attr_native_value = getattr(vehicle_state, self._attribute)
|
self._attr_native_value = getattr(vehicle_state, sensor_key)
|
||||||
elif self._service == SERVICE_LAST_TRIP:
|
elif self._service == SERVICE_LAST_TRIP:
|
||||||
vehicle_last_trip = self._vehicle.state.last_trip
|
vehicle_last_trip = self._vehicle.state.last_trip
|
||||||
if self._attribute == "date_utc":
|
if sensor_key == "date_utc":
|
||||||
date_str = getattr(vehicle_last_trip, "date")
|
date_str = getattr(vehicle_last_trip, "date")
|
||||||
self._attr_native_value = dt_util.parse_datetime(date_str).isoformat()
|
self._attr_native_value = dt_util.parse_datetime(date_str).isoformat()
|
||||||
else:
|
else:
|
||||||
self._attr_native_value = getattr(vehicle_last_trip, self._attribute)
|
self._attr_native_value = getattr(vehicle_last_trip, sensor_key)
|
||||||
elif self._service == SERVICE_ALL_TRIPS:
|
elif self._service == SERVICE_ALL_TRIPS:
|
||||||
vehicle_all_trips = self._vehicle.state.all_trips
|
vehicle_all_trips = self._vehicle.state.all_trips
|
||||||
for attribute in (
|
for attribute in (
|
||||||
@ -513,21 +546,21 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
|||||||
"chargecycle_range",
|
"chargecycle_range",
|
||||||
"total_electric_distance",
|
"total_electric_distance",
|
||||||
):
|
):
|
||||||
if self._attribute.startswith(f"{attribute}_"):
|
if sensor_key.startswith(f"{attribute}_"):
|
||||||
attr = getattr(vehicle_all_trips, attribute)
|
attr = getattr(vehicle_all_trips, attribute)
|
||||||
sub_attr = self._attribute.replace(f"{attribute}_", "")
|
sub_attr = sensor_key.replace(f"{attribute}_", "")
|
||||||
self._attr_native_value = getattr(attr, sub_attr)
|
self._attr_native_value = getattr(attr, sub_attr)
|
||||||
return
|
return
|
||||||
if self._attribute == "reset_date_utc":
|
if sensor_key == "reset_date_utc":
|
||||||
date_str = getattr(vehicle_all_trips, "reset_date")
|
date_str = getattr(vehicle_all_trips, "reset_date")
|
||||||
self._attr_native_value = dt_util.parse_datetime(date_str).isoformat()
|
self._attr_native_value = dt_util.parse_datetime(date_str).isoformat()
|
||||||
else:
|
else:
|
||||||
self._attr_native_value = getattr(vehicle_all_trips, self._attribute)
|
self._attr_native_value = getattr(vehicle_all_trips, sensor_key)
|
||||||
|
|
||||||
vehicle_state = self._vehicle.state
|
vehicle_state = self._vehicle.state
|
||||||
charging_state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
charging_state = vehicle_state.charging_status in [ChargingState.CHARGING]
|
||||||
|
|
||||||
if self._attribute == "charging_level_hv":
|
if sensor_key == "charging_level_hv":
|
||||||
self._attr_icon = icon_for_battery_level(
|
self._attr_icon = icon_for_battery_level(
|
||||||
battery_level=vehicle_state.charging_level_hv, charging=charging_state
|
battery_level=vehicle_state.charging_level_hv, charging=charging_state
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user