Adopt has_entity_name to fix duplicated entity ids on HA 2026.4+ (#1499)

* Adopt has_entity_name to fix duplicated entity ids on HA 2026.4+

Since HA core 2026.4 (PR 166246) composes entity names as device name +
entity name, and only strips the device prefix when the entity name
starts with it. Adaptive Lighting's names ('Adaptive Lighting Sleep
Mode: stairs' on device 'Adaptive Lighting: stairs') never match, so
new installs get ids like
switch.adaptive_lighting_stairs_adaptive_lighting_sleep_mode_stairs.

Adopt has_entity_name: the main switch takes the device name
('Adaptive Lighting: <name>'), the simple switches use their role
('Sleep Mode', 'Adapt Brightness', 'Adapt Color'). Unique ids are
unchanged, so existing installs keep their entity ids via the registry.

Fixes #1459

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Test the new entity ids and that existing ones survive

The renamed constants were defined but never asserted, so neither the
fresh-install ids nor the registry-preservation claim were covered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test: keep the apply-service test light on

Avoid generating brightness zero in the attribute-change helper, which turns the light off and makes the test depend on the current adaptive brightness.

---------

Co-authored-by: proscar87 <proscar87@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Bas Nijholt <bas@nijho.lt>
Co-authored-by: Bas Nijholt <basnijholt@gmail.com>
This commit is contained in:
proscar87 2026-09-06 01:18:49 -06:00 • committed by GitHub
commit 55f871fd0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 9 deletions

View file

@ -155,9 +155,9 @@ ENTITY_LIGHT_2 = "light.light_2"
ENTITY_LIGHT_3 = "light.light_3"
_SWITCH_FMT = f"{SWITCH_DOMAIN}.{DOMAIN}"
ENTITY_SWITCH = f"{_SWITCH_FMT}_{DEFAULT_NAME}"
ENTITY_SLEEP_MODE_SWITCH = f"{_SWITCH_FMT}_sleep_mode_{DEFAULT_NAME}"
ENTITY_ADAPT_BRIGHTNESS_SWITCH = f"{_SWITCH_FMT}_adapt_brightness_{DEFAULT_NAME}"
ENTITY_ADAPT_COLOR_SWITCH = f"{_SWITCH_FMT}_adapt_color_{DEFAULT_NAME}"
ENTITY_SLEEP_MODE_SWITCH = f"{_SWITCH_FMT}_{DEFAULT_NAME}_sleep_mode"
ENTITY_ADAPT_BRIGHTNESS_SWITCH = f"{_SWITCH_FMT}_{DEFAULT_NAME}_adapt_brightness"
ENTITY_ADAPT_COLOR_SWITCH = f"{_SWITCH_FMT}_{DEFAULT_NAME}_adapt_color"
ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE
@ -1092,7 +1092,7 @@ async def test_apply_service(hass):
assert entity_id not in switch.lights
def increased_brightness():
return (light._attr_brightness + 100) % 255
return max(1, (light._attr_brightness + 100) % 255)
def increased_color_temp():
return max(
@ -3254,6 +3254,38 @@ async def test_detect_non_ha_changes_with_separate_turn_on_commands(hass):
), f"AL overrode manual brightness {manual_brightness} with {al_brightness}"
async def test_fresh_install_entity_ids(hass):
"""Test the entity ids a new install gets with device-relative naming."""
_, switch = await setup_switch(hass, {})
assert switch.entity_id == ENTITY_SWITCH
assert switch.sleep_mode_switch.entity_id == ENTITY_SLEEP_MODE_SWITCH
assert switch.adapt_brightness_switch.entity_id == ENTITY_ADAPT_BRIGHTNESS_SWITCH
assert switch.adapt_color_switch.entity_id == ENTITY_ADAPT_COLOR_SWITCH
async def test_existing_entity_ids_are_preserved(hass):
"""Test an install predating this change keeps its entity ids.
The unique ids are unchanged, so the entity registry must keep the
classic `..._sleep_mode_<name>` id instead of renaming the entity.
"""
classic_entity_id = f"{_SWITCH_FMT}_sleep_mode_{DEFAULT_NAME}"
assert classic_entity_id != ENTITY_SLEEP_MODE_SWITCH
registry = entity_registry.async_get(hass)
registry.async_get_or_create(
SWITCH_DOMAIN,
DOMAIN,
f"{DEFAULT_NAME}_sleep_mode",
suggested_object_id=classic_entity_id.split(".", 1)[1],
)
_, switch = await setup_switch(hass, {})
assert switch.sleep_mode_switch.entity_id == classic_entity_id
def test_validate_ui_options_win_over_stale_data():
"""A UI-configured entry's `options` (from the options flow) must win.