Skip to content

Commit

Permalink
Refactor BMW entity availability (home-assistant#110294)
Browse files Browse the repository at this point in the history
Co-authored-by: Richard <[email protected]>
  • Loading branch information
rikroe and rikroe authored Apr 8, 2024
1 parent 487480d commit 16fc935
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 121 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class BMWBinarySensorEntityDescription(BinarySensorEntityDescription):

value_fn: Callable[[MyBMWVehicle], bool]
attr_fn: Callable[[MyBMWVehicle, UnitSystem], dict[str, Any]] | None = None
is_available: Callable[[MyBMWVehicle], bool] = lambda v: v.is_lsc_enabled


SENSOR_TYPES: tuple[BMWBinarySensorEntityDescription, ...] = (
Expand Down Expand Up @@ -174,19 +175,22 @@ class BMWBinarySensorEntityDescription(BinarySensorEntityDescription):
device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
# device class power: On means power detected, Off means no power
value_fn=lambda v: v.fuel_and_battery.charging_status == ChargingState.CHARGING,
is_available=lambda v: v.has_electric_drivetrain,
),
BMWBinarySensorEntityDescription(
key="connection_status",
translation_key="connection_status",
device_class=BinarySensorDeviceClass.PLUG,
value_fn=lambda v: v.fuel_and_battery.is_charger_connected,
is_available=lambda v: v.has_electric_drivetrain,
),
BMWBinarySensorEntityDescription(
key="is_pre_entry_climatization_enabled",
translation_key="is_pre_entry_climatization_enabled",
value_fn=lambda v: v.charging_profile.is_pre_entry_climatization_enabled
if v.charging_profile
else False,
is_available=lambda v: v.has_electric_drivetrain,
),
)

Expand All @@ -203,7 +207,7 @@ async def async_setup_entry(
BMWBinarySensor(coordinator, vehicle, description, hass.config.units)
for vehicle in coordinator.account.vehicles
for description in SENSOR_TYPES
if description.key in vehicle.available_attributes
if description.is_available(vehicle)
]
async_add_entities(entities)

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bmw_connected_drive/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
super().__init__(coordinator, vehicle)

self._attr_unique_id = f"{vehicle.vin}-lock"
self.door_lock_state_available = DOOR_LOCK_STATE in vehicle.available_attributes
self.door_lock_state_available = vehicle.is_lsc_enabled

async def async_lock(self, **kwargs: Any) -> None:
"""Lock the car."""
Expand Down
55 changes: 31 additions & 24 deletions homeassistant/components/bmw_connected_drive/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class BMWSensorEntityDescription(SensorEntityDescription):
key_class: str | None = None
unit_type: str | None = None
value: Callable = lambda x, y: x
is_available: Callable[[MyBMWVehicle], bool] = lambda v: v.is_lsc_enabled


def convert_and_round(
Expand All @@ -53,96 +54,106 @@ def convert_and_round(
return None


SENSOR_TYPES: dict[str, BMWSensorEntityDescription] = {
SENSOR_TYPES: list[BMWSensorEntityDescription] = [
# --- Generic ---
"ac_current_limit": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="ac_current_limit",
translation_key="ac_current_limit",
key_class="charging_profile",
unit_type=UnitOfElectricCurrent.AMPERE,
entity_registry_enabled_default=False,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"charging_start_time": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="charging_start_time",
translation_key="charging_start_time",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.TIMESTAMP,
entity_registry_enabled_default=False,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"charging_end_time": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="charging_end_time",
translation_key="charging_end_time",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.TIMESTAMP,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"charging_status": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="charging_status",
translation_key="charging_status",
key_class="fuel_and_battery",
value=lambda x, y: x.value,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"charging_target": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="charging_target",
translation_key="charging_target",
key_class="fuel_and_battery",
unit_type=PERCENTAGE,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"remaining_battery_percent": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_battery_percent",
translation_key="remaining_battery_percent",
key_class="fuel_and_battery",
unit_type=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
# --- Specific ---
"mileage": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="mileage",
translation_key="mileage",
unit_type=LENGTH,
value=lambda x, hass: convert_and_round(x, hass.config.units.length, 2),
state_class=SensorStateClass.TOTAL_INCREASING,
),
"remaining_range_total": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_range_total",
translation_key="remaining_range_total",
key_class="fuel_and_battery",
unit_type=LENGTH,
value=lambda x, hass: convert_and_round(x, hass.config.units.length, 2),
state_class=SensorStateClass.MEASUREMENT,
),
"remaining_range_electric": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_range_electric",
translation_key="remaining_range_electric",
key_class="fuel_and_battery",
unit_type=LENGTH,
value=lambda x, hass: convert_and_round(x, hass.config.units.length, 2),
state_class=SensorStateClass.MEASUREMENT,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
"remaining_range_fuel": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_range_fuel",
translation_key="remaining_range_fuel",
key_class="fuel_and_battery",
unit_type=LENGTH,
value=lambda x, hass: convert_and_round(x, hass.config.units.length, 2),
state_class=SensorStateClass.MEASUREMENT,
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
"remaining_fuel": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_fuel",
translation_key="remaining_fuel",
key_class="fuel_and_battery",
unit_type=VOLUME,
value=lambda x, hass: convert_and_round(x, hass.config.units.volume, 2),
state_class=SensorStateClass.MEASUREMENT,
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
"remaining_fuel_percent": BMWSensorEntityDescription(
BMWSensorEntityDescription(
key="remaining_fuel_percent",
translation_key="remaining_fuel_percent",
key_class="fuel_and_battery",
unit_type=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
}
]


async def async_setup_entry(
Expand All @@ -153,16 +164,12 @@ async def async_setup_entry(
"""Set up the MyBMW sensors from config entry."""
coordinator: BMWDataUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id]

entities: list[BMWSensor] = []

for vehicle in coordinator.account.vehicles:
entities.extend(
[
BMWSensor(coordinator, vehicle, description)
for attribute_name in vehicle.available_attributes
if (description := SENSOR_TYPES.get(attribute_name))
]
)
entities = [
BMWSensor(coordinator, vehicle, description)
for vehicle in coordinator.account.vehicles
for description in SENSOR_TYPES
if description.is_available(vehicle)
]

async_add_entities(entities)

Expand Down
Loading

0 comments on commit 16fc935

Please sign in to comment.