Do not duplicate device class translations in ring integration (#136868)

pull/137006/head
Steven B. 2025-01-31 12:03:13 +00:00 committed by GitHub
parent f21ab24b8b
commit c7041a97be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 387 additions and 29 deletions

View File

@ -55,7 +55,6 @@ BINARY_SENSOR_TYPES: tuple[RingBinarySensorEntityDescription, ...] = (
),
RingBinarySensorEntityDescription(
key=KIND_MOTION,
translation_key=KIND_MOTION,
device_class=BinarySensorDeviceClass.MOTION,
capability=RingCapability.MOTION_DETECTION,
deprecated_info=DeprecatedInfo(

View File

@ -258,7 +258,6 @@ SENSOR_TYPES: tuple[RingSensorEntityDescription[Any], ...] = (
),
RingSensorEntityDescription[RingGeneric](
key="wifi_signal_strength",
translation_key="wifi_signal_strength",
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
entity_category=EntityCategory.DIAGNOSTIC,

View File

@ -56,9 +56,6 @@
"binary_sensor": {
"ding": {
"name": "Ding"
},
"motion": {
"name": "Motion"
}
},
"event": {
@ -122,9 +119,6 @@
},
"wifi_signal_category": {
"name": "Wi-Fi signal category"
},
"wifi_signal_strength": {
"name": "Wi-Fi signal strength"
}
},
"switch": {

View File

@ -6,6 +6,7 @@ from homeassistant.components.automation import DOMAIN as AUTOMATION_DOMAIN
from homeassistant.components.ring import DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, translation
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry
@ -35,3 +36,62 @@ async def setup_automation(hass: HomeAssistant, alias: str, entity_id: str) -> N
}
},
)
async def async_check_entity_translations(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
config_entry_id: str,
platform_domain: str,
) -> None:
"""Check that entity translations are used correctly.
Check no unused translations in strings.
Check no translation_key defined when translation not in strings.
Check no translation defined when device class translation can be used.
"""
entity_entries = er.async_entries_for_config_entry(entity_registry, config_entry_id)
assert entity_entries
assert len({entity_entry.domain for entity_entry in entity_entries}) == 1, (
"Limit the loaded platforms to 1 platform."
)
translations = await translation.async_get_translations(
hass, "en", "entity", [DOMAIN]
)
device_class_translations = await translation.async_get_translations(
hass, "en", "entity_component", [platform_domain]
)
unique_device_classes = set()
used_translation_keys = set()
for entity_entry in entity_entries:
dc_translation = None
if entity_entry.original_device_class:
dc_translation_key = f"component.{platform_domain}.entity_component.{entity_entry.original_device_class.value}.name"
dc_translation = device_class_translations.get(dc_translation_key)
if entity_entry.translation_key:
key = f"component.{DOMAIN}.entity.{entity_entry.domain}.{entity_entry.translation_key}.name"
entity_translation = translations.get(key)
assert entity_translation, (
f"Translation key {entity_entry.translation_key} defined for {entity_entry.entity_id} not in strings.json"
)
assert dc_translation != entity_translation, (
f"Translation {key} is defined the same as the device class translation."
)
used_translation_keys.add(key)
else:
unique_key = (entity_entry.device_id, entity_entry.original_device_class)
assert unique_key not in unique_device_classes, (
f"No translation key and multiple entities using {entity_entry.original_device_class}"
)
unique_device_classes.add(entity_entry.original_device_class)
for defined_key in translations:
if defined_key.split(".")[3] != platform_domain:
continue
assert defined_key in used_translation_keys, (
f"Translation key {defined_key} unused."
)

View File

@ -75,7 +75,7 @@
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'motion',
'translation_key': None,
'unique_id': '987654-motion',
'unit_of_measurement': None,
})
@ -123,7 +123,7 @@
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'motion',
'translation_key': None,
'unique_id': '765432-motion',
'unit_of_measurement': None,
})
@ -219,7 +219,7 @@
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'motion',
'translation_key': None,
'unique_id': '345678-motion',
'unit_of_measurement': None,
})

View File

@ -117,11 +117,11 @@
}),
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
'original_icon': None,
'original_name': 'Wi-Fi signal strength',
'original_name': 'Signal strength',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi_signal_strength',
'translation_key': None,
'unique_id': '123456-wifi_signal_strength',
'unit_of_measurement': 'dBm',
})
@ -131,7 +131,7 @@
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'signal_strength',
'friendly_name': 'Downstairs Wi-Fi signal strength',
'friendly_name': 'Downstairs Signal strength',
'unit_of_measurement': 'dBm',
}),
'context': <ANY>,
@ -294,6 +294,102 @@
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_door_last_ding-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.front_door_last_ding',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last ding',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_ding',
'unique_id': '987654-last_ding',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.front_door_last_ding-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Front Door Last ding',
}),
'context': <ANY>,
'entity_id': 'sensor.front_door_last_ding',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_door_last_motion-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.front_door_last_motion',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last motion',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_motion',
'unique_id': '987654-last_motion',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.front_door_last_motion-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Front Door Last motion',
}),
'context': <ANY>,
'entity_id': 'sensor.front_door_last_motion',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_door_volume-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -412,11 +508,11 @@
}),
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
'original_icon': None,
'original_name': 'Wi-Fi signal strength',
'original_name': 'Signal strength',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi_signal_strength',
'translation_key': None,
'unique_id': '987654-wifi_signal_strength',
'unit_of_measurement': 'dBm',
})
@ -426,7 +522,7 @@
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'signal_strength',
'friendly_name': 'Front Door Wi-Fi signal strength',
'friendly_name': 'Front Door Signal strength',
'unit_of_measurement': 'dBm',
}),
'context': <ANY>,
@ -485,6 +581,102 @@
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_last_ding-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.front_last_ding',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last ding',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_ding',
'unique_id': '765432-last_ding',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.front_last_ding-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Front Last ding',
}),
'context': <ANY>,
'entity_id': 'sensor.front_last_ding',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_last_motion-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.front_last_motion',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last motion',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_motion',
'unique_id': '765432-last_motion',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.front_last_motion-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Front Last motion',
}),
'context': <ANY>,
'entity_id': 'sensor.front_last_motion',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.front_wifi_signal_category-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -556,11 +748,11 @@
}),
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
'original_icon': None,
'original_name': 'Wi-Fi signal strength',
'original_name': 'Signal strength',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi_signal_strength',
'translation_key': None,
'unique_id': '765432-wifi_signal_strength',
'unit_of_measurement': 'dBm',
})
@ -570,7 +762,7 @@
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'signal_strength',
'friendly_name': 'Front Wi-Fi signal strength',
'friendly_name': 'Front Signal strength',
'unit_of_measurement': 'dBm',
}),
'context': <ANY>,
@ -893,11 +1085,11 @@
}),
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
'original_icon': None,
'original_name': 'Wi-Fi signal strength',
'original_name': 'Signal strength',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi_signal_strength',
'translation_key': None,
'unique_id': '185036587-wifi_signal_strength',
'unit_of_measurement': 'dBm',
})
@ -907,7 +1099,7 @@
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'signal_strength',
'friendly_name': 'Ingress Wi-Fi signal strength',
'friendly_name': 'Ingress Signal strength',
'unit_of_measurement': 'dBm',
}),
'context': <ANY>,
@ -1018,6 +1210,102 @@
'state': 'unknown',
})
# ---
# name: test_states[sensor.internal_last_ding-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.internal_last_ding',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last ding',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_ding',
'unique_id': '345678-last_ding',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.internal_last_ding-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Internal Last ding',
}),
'context': <ANY>,
'entity_id': 'sensor.internal_last_ding',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.internal_last_motion-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.internal_last_motion',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.TIMESTAMP: 'timestamp'>,
'original_icon': None,
'original_name': 'Last motion',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'last_motion',
'unique_id': '345678-last_motion',
'unit_of_measurement': None,
})
# ---
# name: test_states[sensor.internal_last_motion-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'timestamp',
'friendly_name': 'Internal Last motion',
}),
'context': <ANY>,
'entity_id': 'sensor.internal_last_motion',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'unknown',
})
# ---
# name: test_states[sensor.internal_wifi_signal_category-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -1089,11 +1377,11 @@
}),
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
'original_icon': None,
'original_name': 'Wi-Fi signal strength',
'original_name': 'Signal strength',
'platform': 'ring',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'wifi_signal_strength',
'translation_key': None,
'unique_id': '345678-wifi_signal_strength',
'unit_of_measurement': 'dBm',
})
@ -1103,7 +1391,7 @@
'attributes': ReadOnlyDict({
'attribution': 'Data provided by Ring.com',
'device_class': 'signal_strength',
'friendly_name': 'Internal Wi-Fi signal strength',
'friendly_name': 'Internal Signal strength',
'unit_of_measurement': 'dBm',
}),
'context': <ANY>,

View File

@ -18,7 +18,12 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.setup import async_setup_component
from .common import MockConfigEntry, setup_automation, setup_platform
from .common import (
MockConfigEntry,
async_check_entity_translations,
setup_automation,
setup_platform,
)
from .device_mocks import (
FRONT_DEVICE_ID,
FRONT_DOOR_DEVICE_ID,
@ -67,6 +72,9 @@ async def test_states(
) -> None:
"""Test states."""
await setup_platform(hass, Platform.BINARY_SENSOR)
await async_check_entity_translations(
hass, entity_registry, mock_config_entry.entry_id, BINARY_SENSOR_DOMAIN
)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

View File

@ -14,7 +14,7 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .common import MockConfigEntry, setup_platform
from .common import MockConfigEntry, async_check_entity_translations, setup_platform
from tests.common import snapshot_platform
@ -54,6 +54,9 @@ async def test_states(
mock_config_entry.add_to_hass(hass)
await setup_platform(hass, Platform.NUMBER)
await async_check_entity_translations(
hass, entity_registry, mock_config_entry.entry_id, NUMBER_DOMAIN
)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)

View File

@ -16,7 +16,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component
from .common import MockConfigEntry, setup_platform
from .common import MockConfigEntry, async_check_entity_translations, setup_platform
from .device_mocks import (
DOWNSTAIRS_DEVICE_ID,
FRONT_DEVICE_ID,
@ -57,6 +57,10 @@ def create_deprecated_and_disabled_sensor_entities(
create_entry("ingress", "doorbell_volume", INGRESS_DEVICE_ID)
create_entry("ingress", "mic_volume", INGRESS_DEVICE_ID)
create_entry("ingress", "voice_volume", INGRESS_DEVICE_ID)
for desc in ("last_motion", "last_ding"):
create_entry("front", desc, FRONT_DEVICE_ID)
create_entry("front_door", desc, FRONT_DOOR_DEVICE_ID)
create_entry("internal", desc, INTERNAL_DEVICE_ID)
# Disabled
for desc in ("wifi_signal_category", "wifi_signal_strength"):
@ -78,6 +82,9 @@ async def test_states(
"""Test states."""
mock_config_entry.add_to_hass(hass)
await setup_platform(hass, Platform.SENSOR)
await async_check_entity_translations(
hass, entity_registry, mock_config_entry.entry_id, SENSOR_DOMAIN
)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)