Adjust BMW enum sensors translations (#118754)
Co-authored-by: Richard <rikroe@users.noreply.github.com>pull/119147/head
parent
a2504dafbc
commit
43343ea44a
|
@ -28,10 +28,3 @@ SCAN_INTERVALS = {
|
|||
"north_america": 600,
|
||||
"rest_of_world": 300,
|
||||
}
|
||||
|
||||
CLIMATE_ACTIVITY_STATE: list[str] = [
|
||||
"cooling",
|
||||
"heating",
|
||||
"inactive",
|
||||
"standby",
|
||||
]
|
||||
|
|
|
@ -33,8 +33,8 @@ class BMWSelectEntityDescription(SelectEntityDescription):
|
|||
dynamic_options: Callable[[MyBMWVehicle], list[str]] | None = None
|
||||
|
||||
|
||||
SELECT_TYPES: dict[str, BMWSelectEntityDescription] = {
|
||||
"ac_limit": BMWSelectEntityDescription(
|
||||
SELECT_TYPES: tuple[BMWSelectEntityDescription, ...] = (
|
||||
BMWSelectEntityDescription(
|
||||
key="ac_limit",
|
||||
translation_key="ac_limit",
|
||||
is_available=lambda v: v.is_remote_set_ac_limit_enabled,
|
||||
|
@ -48,17 +48,17 @@ SELECT_TYPES: dict[str, BMWSelectEntityDescription] = {
|
|||
),
|
||||
unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||
),
|
||||
"charging_mode": BMWSelectEntityDescription(
|
||||
BMWSelectEntityDescription(
|
||||
key="charging_mode",
|
||||
translation_key="charging_mode",
|
||||
is_available=lambda v: v.is_charging_plan_supported,
|
||||
options=[c.value.lower() for c in ChargingMode if c != ChargingMode.UNKNOWN],
|
||||
current_option=lambda v: str(v.charging_profile.charging_mode.value).lower(), # type: ignore[union-attr]
|
||||
current_option=lambda v: v.charging_profile.charging_mode.value.lower(), # type: ignore[union-attr]
|
||||
remote_service=lambda v, o: v.remote_services.trigger_charging_profile_update(
|
||||
charging_mode=ChargingMode(o)
|
||||
),
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
|
@ -76,7 +76,7 @@ async def async_setup_entry(
|
|||
entities.extend(
|
||||
[
|
||||
BMWSelect(coordinator, vehicle, description)
|
||||
for description in SELECT_TYPES.values()
|
||||
for description in SELECT_TYPES
|
||||
if description.is_available(vehicle)
|
||||
]
|
||||
)
|
||||
|
|
|
@ -9,6 +9,8 @@ import logging
|
|||
|
||||
from bimmer_connected.models import StrEnum, ValueWithUnit
|
||||
from bimmer_connected.vehicle import MyBMWVehicle
|
||||
from bimmer_connected.vehicle.climate import ClimateActivityState
|
||||
from bimmer_connected.vehicle.fuel_and_battery import ChargingState
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
|
@ -29,7 +31,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import BMWBaseEntity
|
||||
from .const import CLIMATE_ACTIVITY_STATE, DOMAIN
|
||||
from .const import DOMAIN
|
||||
from .coordinator import BMWDataUpdateCoordinator
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -73,6 +75,8 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
|
|||
key="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(
|
||||
|
@ -155,7 +159,11 @@ SENSOR_TYPES: list[BMWSensorEntityDescription] = [
|
|||
translation_key="climate_status",
|
||||
key_class="climate",
|
||||
device_class=SensorDeviceClass.ENUM,
|
||||
options=CLIMATE_ACTIVITY_STATE,
|
||||
options=[
|
||||
s.value.lower()
|
||||
for s in ClimateActivityState
|
||||
if s != ClimateActivityState.UNKNOWN
|
||||
],
|
||||
is_available=lambda v: v.is_remote_climate_stop_enabled,
|
||||
),
|
||||
]
|
||||
|
|
|
@ -152,7 +152,22 @@
|
|||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
|
@ -169,7 +184,7 @@
|
|||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Charging status',
|
||||
'platform': 'bmw_connected_drive',
|
||||
|
@ -184,7 +199,22 @@
|
|||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'device_class': 'enum',
|
||||
'friendly_name': 'i3 (+ REX) Charging status',
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.i3_rex_charging_status',
|
||||
|
@ -783,7 +813,22 @@
|
|||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
|
@ -800,7 +845,7 @@
|
|||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Charging status',
|
||||
'platform': 'bmw_connected_drive',
|
||||
|
@ -815,7 +860,22 @@
|
|||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'device_class': 'enum',
|
||||
'friendly_name': 'i4 eDrive40 Charging status',
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.i4_edrive40_charging_status',
|
||||
|
@ -1311,7 +1371,22 @@
|
|||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
|
@ -1328,7 +1403,7 @@
|
|||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Charging status',
|
||||
'platform': 'bmw_connected_drive',
|
||||
|
@ -1343,7 +1418,22 @@
|
|||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'attribution': 'Data provided by MyBMW',
|
||||
'device_class': 'enum',
|
||||
'friendly_name': 'iX xDrive50 Charging status',
|
||||
'options': list([
|
||||
'default',
|
||||
'charging',
|
||||
'error',
|
||||
'complete',
|
||||
'fully_charged',
|
||||
'finished_fully_charged',
|
||||
'finished_not_full',
|
||||
'invalid',
|
||||
'not_charging',
|
||||
'plugged_in',
|
||||
'waiting_for_charging',
|
||||
'target_reached',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.ix_xdrive50_charging_status',
|
||||
|
|
|
@ -8,10 +8,13 @@ import pytest
|
|||
import respx
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN
|
||||
from homeassistant.components.bmw_connected_drive.select import SELECT_TYPES
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
|
||||
from . import check_remote_service_call, setup_mocked_integration
|
||||
|
||||
|
@ -152,3 +155,29 @@ async def test_service_call_fail(
|
|||
target={"entity_id": entity_id},
|
||||
)
|
||||
assert hass.states.get(entity_id).state == old_value
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("bmw_fixture")
|
||||
async def test_entity_option_translations(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Ensure all enum sensor values are translated."""
|
||||
|
||||
# Setup component to load translations
|
||||
assert await setup_mocked_integration(hass)
|
||||
|
||||
prefix = f"component.{BMW_DOMAIN}.entity.{Platform.SELECT.value}"
|
||||
|
||||
translations = await async_get_translations(hass, "en", "entity", [BMW_DOMAIN])
|
||||
translation_states = {
|
||||
k for k in translations if k.startswith(prefix) and ".state." in k
|
||||
}
|
||||
|
||||
sensor_options = {
|
||||
f"{prefix}.{entity_description.translation_key}.state.{option}"
|
||||
for entity_description in SELECT_TYPES
|
||||
if entity_description.options
|
||||
for option in entity_description.options
|
||||
}
|
||||
|
||||
assert sensor_options == translation_states
|
||||
|
|
|
@ -5,9 +5,13 @@ from unittest.mock import patch
|
|||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.bmw_connected_drive import DOMAIN as BMW_DOMAIN
|
||||
from homeassistant.components.bmw_connected_drive.sensor import SENSOR_TYPES
|
||||
from homeassistant.components.sensor.const import SensorDeviceClass
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.helpers.translation import async_get_translations
|
||||
from homeassistant.util.unit_system import (
|
||||
METRIC_SYSTEM as METRIC,
|
||||
US_CUSTOMARY_SYSTEM as IMPERIAL,
|
||||
|
@ -77,3 +81,29 @@ async def test_unit_conversion(
|
|||
entity = hass.states.get(entity_id)
|
||||
assert entity.state == value
|
||||
assert entity.attributes.get("unit_of_measurement") == unit_of_measurement
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("bmw_fixture")
|
||||
async def test_entity_option_translations(
|
||||
hass: HomeAssistant,
|
||||
) -> None:
|
||||
"""Ensure all enum sensor values are translated."""
|
||||
|
||||
# Setup component to load translations
|
||||
assert await setup_mocked_integration(hass)
|
||||
|
||||
prefix = f"component.{BMW_DOMAIN}.entity.{Platform.SENSOR.value}"
|
||||
|
||||
translations = await async_get_translations(hass, "en", "entity", [BMW_DOMAIN])
|
||||
translation_states = {
|
||||
k for k in translations if k.startswith(prefix) and ".state." in k
|
||||
}
|
||||
|
||||
sensor_options = {
|
||||
f"{prefix}.{entity_description.translation_key}.state.{option}"
|
||||
for entity_description in SENSOR_TYPES
|
||||
if entity_description.device_class == SensorDeviceClass.ENUM
|
||||
for option in entity_description.options
|
||||
}
|
||||
|
||||
assert sensor_options == translation_states
|
||||
|
|
Loading…
Reference in New Issue