diff --git a/esphome/core/config.py b/esphome/core/config.py index 3a238e0453..1f40d1608e 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -495,7 +495,9 @@ async def to_code(config: ConfigType) -> None: else: # Old way: string-based area (deprecated) area_slug = slugify(area_conf) - area_id: core.ID = cv.declare_id(Area) + area_id = core.ID( + cv.validate_id_name(area_slug), is_declaration=True, type=Area + ) area_id_str = area_slug _LOGGER.warning( "Using 'area' as a string is deprecated. Please use the new format:\n" @@ -506,7 +508,7 @@ async def to_code(config: ConfigType) -> None: area_conf, ) # Create a synthetic area for backwards compatibility - area_var = cg.Pvariable(area_id) + area_var = cg.new_Pvariable(area_id) area_id_hash = fnv1a_32bit_hash(area_conf) area_name = area_conf diff --git a/tests/integration/fixtures/legacy_area.yaml b/tests/integration/fixtures/legacy_area.yaml new file mode 100644 index 0000000000..4d1617c395 --- /dev/null +++ b/tests/integration/fixtures/legacy_area.yaml @@ -0,0 +1,15 @@ +esphome: + name: legacy-area-test + # Using legacy string-based area configuration + area: Master Bedroom + +host: +api: +logger: + +# Simple sensor to ensure the device compiles and runs +sensor: + - platform: template + name: Test Sensor + lambda: return 42.0; + update_interval: 1s diff --git a/tests/integration/test_legacy_area.py b/tests/integration/test_legacy_area.py new file mode 100644 index 0000000000..d10a01ec6a --- /dev/null +++ b/tests/integration/test_legacy_area.py @@ -0,0 +1,41 @@ +"""Integration test for legacy string-based area configuration.""" + +from __future__ import annotations + +import pytest + +from .types import APIClientConnectedFactory, RunCompiledFunction + + +@pytest.mark.asyncio +async def test_legacy_area( + yaml_config: str, + run_compiled: RunCompiledFunction, + api_client_connected: APIClientConnectedFactory, +) -> None: + """Test legacy string-based area configuration.""" + async with run_compiled(yaml_config), api_client_connected() as client: + # Get device info which includes areas + device_info = await client.device_info() + assert device_info is not None + + # Verify the area is reported (should be converted to structured format) + areas = device_info.areas + assert len(areas) == 1, f"Expected exactly 1 area, got {len(areas)}" + + # Find the area - should be slugified from "Master Bedroom" + area = areas[0] + assert area.name == "Master Bedroom", ( + f"Expected area name 'Master Bedroom', got '{area.name}'" + ) + + # Verify area.id is set (it should be a hash) + assert area.area_id > 0, "Area ID should be a positive hash value" + + # The suggested_area field should be set for backward compatibility + assert device_info.suggested_area == "Master Bedroom", ( + f"Expected suggested_area to be 'Master Bedroom', got '{device_info.suggested_area}'" + ) + + # Verify deprecated warning would have been logged during compilation + # (We can't check logs directly in integration tests, but the code should work)