mirror of
https://github.com/home-assistant/core.git
synced 2025-07-26 06:37:52 +00:00
Add AllTrips sensors for BMW Connected Drive (#50420)
* Add AllTrips sensors for BMW Connected Drive Added several new AllTrips sensors and some optional extra AllTrips sensors (disabled by default) * Fix for failed checks * Fix for failed check (black) * Code tidying Changed code after useful comments ;)
This commit is contained in:
parent
c865a1876e
commit
11d7efb785
@ -1,7 +1,7 @@
|
|||||||
"""Support for reading vehicle status from BMW connected drive portal."""
|
"""Support for reading vehicle status from BMW connected drive portal."""
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from bimmer_connected.const import 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 homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import SensorEntity
|
||||||
@ -9,8 +9,10 @@ from homeassistant.const import (
|
|||||||
CONF_UNIT_SYSTEM_IMPERIAL,
|
CONF_UNIT_SYSTEM_IMPERIAL,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
ENERGY_WATT_HOUR,
|
||||||
LENGTH_KILOMETERS,
|
LENGTH_KILOMETERS,
|
||||||
LENGTH_MILES,
|
LENGTH_MILES,
|
||||||
|
MASS_KILOGRAMS,
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
TIME_HOURS,
|
TIME_HOURS,
|
||||||
TIME_MINUTES,
|
TIME_MINUTES,
|
||||||
@ -60,6 +62,146 @@ ATTR_TO_HA_METRIC = {
|
|||||||
"electric_distance": ["mdi:map-marker-distance", None, LENGTH_KILOMETERS, True],
|
"electric_distance": ["mdi:map-marker-distance", None, LENGTH_KILOMETERS, True],
|
||||||
"saved_fuel": ["mdi:fuel", None, VOLUME_LITERS, False],
|
"saved_fuel": ["mdi:fuel", None, VOLUME_LITERS, False],
|
||||||
"total_distance": ["mdi:map-marker-distance", None, LENGTH_KILOMETERS, True],
|
"total_distance": ["mdi:map-marker-distance", None, LENGTH_KILOMETERS, True],
|
||||||
|
# AllTrips attributes
|
||||||
|
"average_combined_consumption_community_average": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_community_high": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_community_low": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_user_average": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_average": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_high": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_low": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_user_average": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_average": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_high": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_low": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_user_average": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_KILOMETERS}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_low": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_current_charge_cycle": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_low": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_user_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_user_total": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_KILOMETERS,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_saved_fuel": ["mdi:fuel", None, VOLUME_LITERS, False],
|
||||||
}
|
}
|
||||||
|
|
||||||
ATTR_TO_HA_IMPERIAL = {
|
ATTR_TO_HA_IMPERIAL = {
|
||||||
@ -92,6 +234,146 @@ ATTR_TO_HA_IMPERIAL = {
|
|||||||
"electric_distance": ["mdi:map-marker-distance", None, LENGTH_MILES, True],
|
"electric_distance": ["mdi:map-marker-distance", None, LENGTH_MILES, True],
|
||||||
"saved_fuel": ["mdi:fuel", None, VOLUME_GALLONS, False],
|
"saved_fuel": ["mdi:fuel", None, VOLUME_GALLONS, False],
|
||||||
"total_distance": ["mdi:map-marker-distance", None, LENGTH_MILES, True],
|
"total_distance": ["mdi:map-marker-distance", None, LENGTH_MILES, True],
|
||||||
|
# AllTrips attributes
|
||||||
|
"average_combined_consumption_community_average": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_community_high": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_community_low": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_combined_consumption_user_average": [
|
||||||
|
"mdi:flash",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_average": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_high": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_community_low": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_electric_consumption_user_average": [
|
||||||
|
"mdi:power-plug-outline",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_average": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_high": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_community_low": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"average_recuperation_user_average": [
|
||||||
|
"mdi:recycle-variant",
|
||||||
|
None,
|
||||||
|
f"{ENERGY_KILO_WATT_HOUR}/100{LENGTH_MILES}",
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_community_low": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_current_charge_cycle": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"chargecycle_range_user_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
True,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_high": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_community_low": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_user_average": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_electric_distance_user_total": [
|
||||||
|
"mdi:map-marker-distance",
|
||||||
|
None,
|
||||||
|
LENGTH_MILES,
|
||||||
|
False,
|
||||||
|
],
|
||||||
|
"total_saved_fuel": ["mdi:fuel", None, VOLUME_GALLONS, False],
|
||||||
}
|
}
|
||||||
|
|
||||||
ATTR_TO_HA_GENERIC = {
|
ATTR_TO_HA_GENERIC = {
|
||||||
@ -104,6 +386,11 @@ ATTR_TO_HA_GENERIC = {
|
|||||||
"date_utc": [None, DEVICE_CLASS_TIMESTAMP, None, True],
|
"date_utc": [None, DEVICE_CLASS_TIMESTAMP, None, True],
|
||||||
"duration": ["mdi:timer-outline", None, TIME_MINUTES, True],
|
"duration": ["mdi:timer-outline", None, TIME_MINUTES, True],
|
||||||
"electric_distance_ratio": ["mdi:percent-outline", None, PERCENTAGE, False],
|
"electric_distance_ratio": ["mdi:percent-outline", None, PERCENTAGE, False],
|
||||||
|
# AllTrips attributes
|
||||||
|
"battery_size_max": ["mdi:battery-charging-high", None, ENERGY_WATT_HOUR, False],
|
||||||
|
"reset_date_utc": [None, DEVICE_CLASS_TIMESTAMP, None, False],
|
||||||
|
"saved_co2": ["mdi:tree-outline", None, MASS_KILOGRAMS, False],
|
||||||
|
"saved_co2_green_energy": ["mdi:tree-outline", None, MASS_KILOGRAMS, False],
|
||||||
}
|
}
|
||||||
|
|
||||||
ATTR_TO_HA_METRIC.update(ATTR_TO_HA_GENERIC)
|
ATTR_TO_HA_METRIC.update(ATTR_TO_HA_GENERIC)
|
||||||
@ -112,6 +399,7 @@ ATTR_TO_HA_IMPERIAL.update(ATTR_TO_HA_GENERIC)
|
|||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
"""Set up the BMW ConnectedDrive sensors from config entry."""
|
"""Set up the BMW ConnectedDrive sensors from config entry."""
|
||||||
|
# pylint: disable=too-many-nested-blocks
|
||||||
if hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL:
|
if hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL:
|
||||||
attribute_info = ATTR_TO_HA_IMPERIAL
|
attribute_info = ATTR_TO_HA_IMPERIAL
|
||||||
else:
|
else:
|
||||||
@ -145,6 +433,63 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
account, vehicle, attribute_name, attribute_info, service
|
account, vehicle, attribute_name, attribute_info, service
|
||||||
)
|
)
|
||||||
entities.append(device)
|
entities.append(device)
|
||||||
|
if service == SERVICE_ALL_TRIPS:
|
||||||
|
for attribute_name in vehicle.state.all_trips.available_attributes:
|
||||||
|
if attribute_name == "reset_date":
|
||||||
|
device = BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
"reset_date_utc",
|
||||||
|
attribute_info,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
entities.append(device)
|
||||||
|
elif attribute_name in (
|
||||||
|
"average_combined_consumption",
|
||||||
|
"average_electric_consumption",
|
||||||
|
"average_recuperation",
|
||||||
|
"chargecycle_range",
|
||||||
|
"total_electric_distance",
|
||||||
|
):
|
||||||
|
for attr in [
|
||||||
|
"community_average",
|
||||||
|
"community_high",
|
||||||
|
"community_low",
|
||||||
|
"user_average",
|
||||||
|
]:
|
||||||
|
device = BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
f"{attribute_name}_{attr}",
|
||||||
|
attribute_info,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
entities.append(device)
|
||||||
|
if attribute_name == "chargecycle_range":
|
||||||
|
for attr in ["user_current_charge_cycle", "user_high"]:
|
||||||
|
device = BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
f"{attribute_name}_{attr}",
|
||||||
|
attribute_info,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
entities.append(device)
|
||||||
|
if attribute_name == "total_electric_distance":
|
||||||
|
for attr in ["user_total"]:
|
||||||
|
device = BMWConnectedDriveSensor(
|
||||||
|
account,
|
||||||
|
vehicle,
|
||||||
|
f"{attribute_name}_{attr}",
|
||||||
|
attribute_info,
|
||||||
|
service,
|
||||||
|
)
|
||||||
|
entities.append(device)
|
||||||
|
else:
|
||||||
|
device = BMWConnectedDriveSensor(
|
||||||
|
account, vehicle, attribute_name, attribute_info, service
|
||||||
|
)
|
||||||
|
entities.append(device)
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
@ -227,7 +572,6 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
|||||||
"""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
|
||||||
vehicle_last_trip = self._vehicle.state.last_trip
|
|
||||||
if self._attribute == "charging_status":
|
if self._attribute == "charging_status":
|
||||||
self._state = getattr(vehicle_state, self._attribute).value
|
self._state = getattr(vehicle_state, self._attribute).value
|
||||||
elif self.unit_of_measurement == VOLUME_GALLONS:
|
elif self.unit_of_measurement == VOLUME_GALLONS:
|
||||||
@ -241,8 +585,28 @@ class BMWConnectedDriveSensor(BMWConnectedDriveBaseEntity, SensorEntity):
|
|||||||
elif self._service is None:
|
elif self._service is None:
|
||||||
self._state = getattr(vehicle_state, self._attribute)
|
self._state = getattr(vehicle_state, self._attribute)
|
||||||
elif self._service == SERVICE_LAST_TRIP:
|
elif self._service == SERVICE_LAST_TRIP:
|
||||||
|
vehicle_last_trip = self._vehicle.state.last_trip
|
||||||
if self._attribute == "date_utc":
|
if self._attribute == "date_utc":
|
||||||
date_str = getattr(vehicle_last_trip, "date")
|
date_str = getattr(vehicle_last_trip, "date")
|
||||||
self._state = dt_util.parse_datetime(date_str).isoformat()
|
self._state = dt_util.parse_datetime(date_str).isoformat()
|
||||||
else:
|
else:
|
||||||
self._state = getattr(vehicle_last_trip, self._attribute)
|
self._state = getattr(vehicle_last_trip, self._attribute)
|
||||||
|
elif self._service == SERVICE_ALL_TRIPS:
|
||||||
|
vehicle_all_trips = self._vehicle.state.all_trips
|
||||||
|
for attribute in [
|
||||||
|
"average_combined_consumption",
|
||||||
|
"average_electric_consumption",
|
||||||
|
"average_recuperation",
|
||||||
|
"chargecycle_range",
|
||||||
|
"total_electric_distance",
|
||||||
|
]:
|
||||||
|
if self._attribute.startswith(f"{attribute}_"):
|
||||||
|
attr = getattr(vehicle_all_trips, attribute)
|
||||||
|
sub_attr = self._attribute.replace(f"{attribute}_", "")
|
||||||
|
self._state = getattr(attr, sub_attr)
|
||||||
|
return
|
||||||
|
if self._attribute == "reset_date_utc":
|
||||||
|
date_str = getattr(vehicle_all_trips, "reset_date")
|
||||||
|
self._state = dt_util.parse_datetime(date_str).isoformat()
|
||||||
|
else:
|
||||||
|
self._state = getattr(vehicle_all_trips, self._attribute)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user