Exclude internal entities from name uniqueness validation (#9410)

This commit is contained in:
J. Nick Koston 2025-07-09 22:34:01 -10:00 committed by Jesse Hills
parent 5ba493acc3
commit 23dd2d648e
No known key found for this signature in database
GPG Key ID: BEAAE804EFD8E83A
2 changed files with 51 additions and 12 deletions

View File

@ -187,6 +187,12 @@ def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigTy
# No name to validate # No name to validate
return config return config
# Skip validation for internal entities
# Internal entities are not exposed to Home Assistant and don't use the hash-based
# entity state tracking system, so name collisions don't matter for them
if config.get(CONF_INTERNAL, False):
return config
# Get the entity name # Get the entity name
entity_name = config[CONF_NAME] entity_name = config[CONF_NAME]

View File

@ -8,9 +8,19 @@ from typing import Any
import pytest import pytest
from esphome.config_validation import Invalid from esphome.config_validation import Invalid
from esphome.const import CONF_DEVICE_ID, CONF_DISABLED_BY_DEFAULT, CONF_ICON, CONF_NAME from esphome.const import (
CONF_DEVICE_ID,
CONF_DISABLED_BY_DEFAULT,
CONF_ICON,
CONF_INTERNAL,
CONF_NAME,
)
from esphome.core import CORE, ID, entity_helpers from esphome.core import CORE, ID, entity_helpers
from esphome.core.entity_helpers import get_base_entity_object_id, setup_entity from esphome.core.entity_helpers import (
entity_duplicate_validator,
get_base_entity_object_id,
setup_entity,
)
from esphome.cpp_generator import MockObj from esphome.cpp_generator import MockObj
from esphome.helpers import sanitize, snake_case from esphome.helpers import sanitize, snake_case
@ -493,11 +503,6 @@ async def test_setup_entity_disabled_by_default(
def test_entity_duplicate_validator() -> None: def test_entity_duplicate_validator() -> None:
"""Test the entity_duplicate_validator function.""" """Test the entity_duplicate_validator function."""
from esphome.core.entity_helpers import entity_duplicate_validator
# Reset CORE unique_ids for clean test
CORE.unique_ids.clear()
# Create validator for sensor platform # Create validator for sensor platform
validator = entity_duplicate_validator("sensor") validator = entity_duplicate_validator("sensor")
@ -523,11 +528,6 @@ def test_entity_duplicate_validator() -> None:
def test_entity_duplicate_validator_with_devices() -> None: def test_entity_duplicate_validator_with_devices() -> None:
"""Test entity_duplicate_validator with devices.""" """Test entity_duplicate_validator with devices."""
from esphome.core.entity_helpers import entity_duplicate_validator
# Reset CORE unique_ids for clean test
CORE.unique_ids.clear()
# Create validator for sensor platform # Create validator for sensor platform
validator = entity_duplicate_validator("sensor") validator = entity_duplicate_validator("sensor")
@ -605,3 +605,36 @@ def test_entity_different_platforms_yaml_validation(
) )
# This should succeed # This should succeed
assert result is not None assert result is not None
def test_entity_duplicate_validator_internal_entities() -> None:
"""Test that internal entities are excluded from duplicate name validation."""
# Create validator for sensor platform
validator = entity_duplicate_validator("sensor")
# First entity should pass
config1 = {CONF_NAME: "Temperature"}
validated1 = validator(config1)
assert validated1 == config1
assert ("sensor", "temperature") in CORE.unique_ids
# Internal entity with same name should pass (not added to unique_ids)
config2 = {CONF_NAME: "Temperature", CONF_INTERNAL: True}
validated2 = validator(config2)
assert validated2 == config2
# Internal entity should not be added to unique_ids
assert len([k for k in CORE.unique_ids if k == ("sensor", "temperature")]) == 1
# Another internal entity with same name should also pass
config3 = {CONF_NAME: "Temperature", CONF_INTERNAL: True}
validated3 = validator(config3)
assert validated3 == config3
# Still only one entry in unique_ids (from the non-internal entity)
assert len([k for k in CORE.unique_ids if k == ("sensor", "temperature")]) == 1
# Non-internal entity with same name should fail
config4 = {CONF_NAME: "Temperature"}
with pytest.raises(
Invalid, match=r"Duplicate sensor entity with name 'Temperature' found"
):
validator(config4)