diff --git a/esphome/config.py b/esphome/config.py index 634dba8dad..e508ca585b 100644 --- a/esphome/config.py +++ b/esphome/config.py @@ -319,6 +319,9 @@ def iter_ids(config, path=None): yield from iter_ids(item, path + [i]) elif isinstance(config, dict): for key, value in config.items(): + if len(path) == 0 and key == CONF_SUBSTITUTIONS: + # Ignore IDs in substitution definitions. + continue if isinstance(key, core.ID): yield key, path yield from iter_ids(value, path + [key]) diff --git a/tests/unit_tests/core/test_config.py b/tests/unit_tests/core/test_config.py index a1e4627dc9..90b2f5edba 100644 --- a/tests/unit_tests/core/test_config.py +++ b/tests/unit_tests/core/test_config.py @@ -261,6 +261,17 @@ def test_device_duplicate_id( assert "ID duplicate_device redefined!" in captured.out +def test_substitution_with_id( + yaml_file: Callable[[str], str], capsys: pytest.CaptureFixture[str] +) -> None: + """Test that a ids coming from substitutions do not cause false positive ID redefinition.""" + load_config_from_fixture( + yaml_file, "id_collision_with_substitution.yaml", FIXTURES_DIR + ) + captured = capsys.readouterr() + assert "ID some_switch_id redefined!" not in captured.out + + def test_add_platform_defines_priority() -> None: """Test that _add_platform_defines runs after globals. diff --git a/tests/unit_tests/fixtures/core/config/id_collision_with_substitution.yaml b/tests/unit_tests/fixtures/core/config/id_collision_with_substitution.yaml new file mode 100644 index 0000000000..840d9ac925 --- /dev/null +++ b/tests/unit_tests/fixtures/core/config/id_collision_with_substitution.yaml @@ -0,0 +1,12 @@ +esphome: + name: test + +host: + +substitutions: + support_switches: + - platform: gpio + id: some_switch_id + pin: 12 + +switch: $support_switches