Refactor BMW sensors and migrate unique_ids (#121380)

This commit is contained in:
Richard Kroegel 2024-07-06 17:34:20 +02:00 committed by GitHub
parent cf34b46b5a
commit 48145c1a7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 82 additions and 72 deletions

View file

@ -87,8 +87,20 @@ async def _async_migrate_entries(
@callback
def update_unique_id(entry: er.RegistryEntry) -> dict[str, str] | None:
replacements = {
"charging_level_hv": "remaining_battery_percent",
"fuel_percent": "remaining_fuel_percent",
"charging_level_hv": "fuel_and_battery.remaining_battery_percent",
"fuel_percent": "fuel_and_battery.remaining_fuel_percent",
"ac_current_limit": "charging_profile.ac_current_limit",
"charging_start_time": "fuel_and_battery.charging_start_time",
"charging_end_time": "fuel_and_battery.charging_end_time",
"charging_status": "fuel_and_battery.charging_status",
"charging_target": "fuel_and_battery.charging_target",
"remaining_battery_percent": "fuel_and_battery.remaining_battery_percent",
"remaining_range_total": "fuel_and_battery.remaining_range_total",
"remaining_range_electric": "fuel_and_battery.remaining_range_electric",
"remaining_range_fuel": "fuel_and_battery.remaining_range_fuel",
"remaining_fuel": "fuel_and_battery.remaining_fuel",
"remaining_fuel_percent": "fuel_and_battery.remaining_fuel_percent",
"activity": "climate.activity",
}
if (key := entry.unique_id.split("-")[-1]) in replacements:
new_unique_id = entry.unique_id.replace(key, replacements[key])

View file

@ -46,9 +46,8 @@ class BMWSensorEntityDescription(SensorEntityDescription):
SENSOR_TYPES: list[BMWSensorEntityDescription] = [
BMWSensorEntityDescription(
key="ac_current_limit",
key="charging_profile.ac_current_limit",
translation_key="ac_current_limit",
key_class="charging_profile",
device_class=SensorDeviceClass.CURRENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
entity_registry_enabled_default=False,
@ -56,41 +55,36 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
BMWSensorEntityDescription(
key="charging_start_time",
key="fuel_and_battery.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,
),
BMWSensorEntityDescription(
key="charging_end_time",
key="fuel_and_battery.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,
),
BMWSensorEntityDescription(
key="charging_status",
key="fuel_and_battery.charging_status",
translation_key="charging_status",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.ENUM,
options=[s.value.lower() for s in ChargingState if s != ChargingState.UNKNOWN],
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
BMWSensorEntityDescription(
key="charging_target",
key="fuel_and_battery.charging_target",
translation_key="charging_target",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
suggested_display_precision=0,
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
BMWSensorEntityDescription(
key="remaining_battery_percent",
key="fuel_and_battery.remaining_battery_percent",
translation_key="remaining_battery_percent",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.BATTERY,
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
@ -106,18 +100,16 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
suggested_display_precision=0,
),
BMWSensorEntityDescription(
key="remaining_range_total",
key="fuel_and_battery.remaining_range_total",
translation_key="remaining_range_total",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=UnitOfLength.KILOMETERS,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
),
BMWSensorEntityDescription(
key="remaining_range_electric",
key="fuel_and_battery.remaining_range_electric",
translation_key="remaining_range_electric",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=UnitOfLength.KILOMETERS,
state_class=SensorStateClass.MEASUREMENT,
@ -125,9 +117,8 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
is_available=lambda v: v.is_lsc_enabled and v.has_electric_drivetrain,
),
BMWSensorEntityDescription(
key="remaining_range_fuel",
key="fuel_and_battery.remaining_range_fuel",
translation_key="remaining_range_fuel",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.DISTANCE,
native_unit_of_measurement=UnitOfLength.KILOMETERS,
state_class=SensorStateClass.MEASUREMENT,
@ -135,9 +126,8 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
BMWSensorEntityDescription(
key="remaining_fuel",
key="fuel_and_battery.remaining_fuel",
translation_key="remaining_fuel",
key_class="fuel_and_battery",
device_class=SensorDeviceClass.VOLUME,
native_unit_of_measurement=UnitOfVolume.LITERS,
state_class=SensorStateClass.MEASUREMENT,
@ -145,18 +135,16 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
BMWSensorEntityDescription(
key="remaining_fuel_percent",
key="fuel_and_battery.remaining_fuel_percent",
translation_key="remaining_fuel_percent",
key_class="fuel_and_battery",
native_unit_of_measurement=PERCENTAGE,
state_class=SensorStateClass.MEASUREMENT,
suggested_display_precision=0,
is_available=lambda v: v.is_lsc_enabled and v.has_combustion_drivetrain,
),
BMWSensorEntityDescription(
key="activity",
key="climate.activity",
translation_key="climate_status",
key_class="climate",
device_class=SensorDeviceClass.ENUM,
options=[
s.value.lower()
@ -208,13 +196,12 @@ class BMWSensor(BMWBaseEntity, SensorEntity):
_LOGGER.debug(
"Updating sensor '%s' of %s", self.entity_description.key, self.vehicle.name
)
if self.entity_description.key_class is None:
state = getattr(self.vehicle, self.entity_description.key)
else:
state = getattr(
getattr(self.vehicle, self.entity_description.key_class),
self.entity_description.key,
)
key_path = self.entity_description.key.split(".")
state = getattr(self.vehicle, key_path.pop(0))
for key in key_path:
state = getattr(state, key)
# For datetime without tzinfo, we assume it to be the same timezone as the HA instance
if isinstance(state, datetime.datetime) and state.tzinfo is None:

View file

@ -31,7 +31,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'ac_current_limit',
'unique_id': 'WBY00000000REXI01-ac_current_limit',
'unique_id': 'WBY00000000REXI01-charging_profile.ac_current_limit',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
@ -79,7 +79,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_end_time',
'unique_id': 'WBY00000000REXI01-charging_end_time',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.charging_end_time',
'unit_of_measurement': None,
})
# ---
@ -126,7 +126,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_start_time',
'unique_id': 'WBY00000000REXI01-charging_start_time',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.charging_start_time',
'unit_of_measurement': None,
})
# ---
@ -188,7 +188,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBY00000000REXI01-charging_status',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.charging_status',
'unit_of_measurement': None,
})
# ---
@ -252,7 +252,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_target',
'unique_id': 'WBY00000000REXI01-charging_target',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.charging_target',
'unit_of_measurement': '%',
})
# ---
@ -359,7 +359,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_battery_percent',
'unique_id': 'WBY00000000REXI01-remaining_battery_percent',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_battery_percent',
'unit_of_measurement': '%',
})
# ---
@ -413,7 +413,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_fuel',
'unique_id': 'WBY00000000REXI01-remaining_fuel',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_fuel',
'unit_of_measurement': <UnitOfVolume.LITERS: 'L'>,
})
# ---
@ -467,7 +467,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_fuel_percent',
'unique_id': 'WBY00000000REXI01-remaining_fuel_percent',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_fuel_percent',
'unit_of_measurement': '%',
})
# ---
@ -520,7 +520,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_electric',
'unique_id': 'WBY00000000REXI01-remaining_range_electric',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_range_electric',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -574,7 +574,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_fuel',
'unique_id': 'WBY00000000REXI01-remaining_range_fuel',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_range_fuel',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -628,7 +628,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_total',
'unique_id': 'WBY00000000REXI01-remaining_range_total',
'unique_id': 'WBY00000000REXI01-fuel_and_battery.remaining_range_total',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -680,7 +680,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'ac_current_limit',
'unique_id': 'WBA00000000DEMO02-ac_current_limit',
'unique_id': 'WBA00000000DEMO02-charging_profile.ac_current_limit',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
@ -728,7 +728,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_end_time',
'unique_id': 'WBA00000000DEMO02-charging_end_time',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.charging_end_time',
'unit_of_measurement': None,
})
# ---
@ -775,7 +775,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_start_time',
'unique_id': 'WBA00000000DEMO02-charging_start_time',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.charging_start_time',
'unit_of_measurement': None,
})
# ---
@ -837,7 +837,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBA00000000DEMO02-charging_status',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.charging_status',
'unit_of_measurement': None,
})
# ---
@ -901,7 +901,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_target',
'unique_id': 'WBA00000000DEMO02-charging_target',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.charging_target',
'unit_of_measurement': '%',
})
# ---
@ -956,7 +956,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'climate_status',
'unique_id': 'WBA00000000DEMO02-activity',
'unique_id': 'WBA00000000DEMO02-climate.activity',
'unit_of_measurement': None,
})
# ---
@ -1068,7 +1068,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_battery_percent',
'unique_id': 'WBA00000000DEMO02-remaining_battery_percent',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.remaining_battery_percent',
'unit_of_measurement': '%',
})
# ---
@ -1122,7 +1122,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_electric',
'unique_id': 'WBA00000000DEMO02-remaining_range_electric',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.remaining_range_electric',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -1176,7 +1176,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_total',
'unique_id': 'WBA00000000DEMO02-remaining_range_total',
'unique_id': 'WBA00000000DEMO02-fuel_and_battery.remaining_range_total',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -1228,7 +1228,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'ac_current_limit',
'unique_id': 'WBA00000000DEMO01-ac_current_limit',
'unique_id': 'WBA00000000DEMO01-charging_profile.ac_current_limit',
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
})
# ---
@ -1276,7 +1276,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_end_time',
'unique_id': 'WBA00000000DEMO01-charging_end_time',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.charging_end_time',
'unit_of_measurement': None,
})
# ---
@ -1323,7 +1323,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_start_time',
'unique_id': 'WBA00000000DEMO01-charging_start_time',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.charging_start_time',
'unit_of_measurement': None,
})
# ---
@ -1385,7 +1385,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_status',
'unique_id': 'WBA00000000DEMO01-charging_status',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.charging_status',
'unit_of_measurement': None,
})
# ---
@ -1449,7 +1449,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charging_target',
'unique_id': 'WBA00000000DEMO01-charging_target',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.charging_target',
'unit_of_measurement': '%',
})
# ---
@ -1504,7 +1504,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'climate_status',
'unique_id': 'WBA00000000DEMO01-activity',
'unique_id': 'WBA00000000DEMO01-climate.activity',
'unit_of_measurement': None,
})
# ---
@ -1616,7 +1616,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_battery_percent',
'unique_id': 'WBA00000000DEMO01-remaining_battery_percent',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.remaining_battery_percent',
'unit_of_measurement': '%',
})
# ---
@ -1670,7 +1670,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_electric',
'unique_id': 'WBA00000000DEMO01-remaining_range_electric',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.remaining_range_electric',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -1724,7 +1724,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_total',
'unique_id': 'WBA00000000DEMO01-remaining_range_total',
'unique_id': 'WBA00000000DEMO01-fuel_and_battery.remaining_range_total',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -1780,7 +1780,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'climate_status',
'unique_id': 'WBA00000000DEMO03-activity',
'unique_id': 'WBA00000000DEMO03-climate.activity',
'unit_of_measurement': None,
})
# ---
@ -1892,7 +1892,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_fuel',
'unique_id': 'WBA00000000DEMO03-remaining_fuel',
'unique_id': 'WBA00000000DEMO03-fuel_and_battery.remaining_fuel',
'unit_of_measurement': <UnitOfVolume.LITERS: 'L'>,
})
# ---
@ -1946,7 +1946,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_fuel_percent',
'unique_id': 'WBA00000000DEMO03-remaining_fuel_percent',
'unique_id': 'WBA00000000DEMO03-fuel_and_battery.remaining_fuel_percent',
'unit_of_measurement': '%',
})
# ---
@ -1999,7 +1999,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_fuel',
'unique_id': 'WBA00000000DEMO03-remaining_range_fuel',
'unique_id': 'WBA00000000DEMO03-fuel_and_battery.remaining_range_fuel',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---
@ -2053,7 +2053,7 @@
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'remaining_range_total',
'unique_id': 'WBA00000000DEMO03-remaining_range_total',
'unique_id': 'WBA00000000DEMO03-fuel_and_battery.remaining_range_total',
'unit_of_measurement': <UnitOfLength.KILOMETERS: 'km'>,
})
# ---

View file

@ -85,7 +85,7 @@ async def test_migrate_options_from_data(hass: HomeAssistant) -> None:
"disabled_by": None,
},
f"{VIN}-charging_level_hv",
f"{VIN}-remaining_battery_percent",
f"{VIN}-fuel_and_battery.remaining_battery_percent",
),
(
{
@ -96,7 +96,18 @@ async def test_migrate_options_from_data(hass: HomeAssistant) -> None:
"disabled_by": None,
},
f"{VIN}-remaining_range_total",
f"{VIN}-remaining_range_total",
f"{VIN}-fuel_and_battery.remaining_range_total",
),
(
{
"domain": SENSOR_DOMAIN,
"platform": BMW_DOMAIN,
"unique_id": f"{VIN}-mileage",
"suggested_object_id": f"{VEHICLE_NAME} mileage",
"disabled_by": None,
},
f"{VIN}-mileage",
f"{VIN}-mileage",
),
],
)
@ -143,7 +154,7 @@ async def test_migrate_unique_ids(
"disabled_by": None,
},
f"{VIN}-charging_level_hv",
f"{VIN}-remaining_battery_percent",
f"{VIN}-fuel_and_battery.remaining_battery_percent",
),
],
)
@ -163,8 +174,8 @@ async def test_dont_migrate_unique_ids(
existing_entity = entity_registry.async_get_or_create(
SENSOR_DOMAIN,
BMW_DOMAIN,
unique_id=f"{VIN}-remaining_battery_percent",
suggested_object_id=f"{VEHICLE_NAME} remaining_battery_percent",
unique_id=f"{VIN}-fuel_and_battery.remaining_battery_percent",
suggested_object_id=f"{VEHICLE_NAME} fuel_and_battery.remaining_battery_percent",
config_entry=mock_config_entry,
)