Revert "Fix entities/devices stuck in disabled state after config entry re-add" (#151158)

This commit is contained in:
Erik Montnemery
2025-08-25 22:48:30 +02:00
committed by GitHub
parent 05c8e8b4fd
commit 58339d79d3
4 changed files with 1 additions and 198 deletions

View File

@@ -1460,18 +1460,12 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
if config_entry_id not in config_entries:
continue
if config_entries == {config_entry_id}:
# Clear disabled_by if it was disabled by the config entry
if deleted_device.disabled_by is DeviceEntryDisabler.CONFIG_ENTRY:
disabled_by = None
else:
disabled_by = deleted_device.disabled_by
# Add a time stamp when the deleted device became orphaned
self.deleted_devices[deleted_device.id] = attr.evolve(
deleted_device,
orphaned_timestamp=now_time,
config_entries=set(),
config_entries_subentries={},
disabled_by=disabled_by,
)
else:
config_entries = config_entries - {config_entry_id}

View File

@@ -1622,17 +1622,9 @@ class EntityRegistry(BaseRegistry):
for key, deleted_entity in list(self.deleted_entities.items()):
if config_entry_id != deleted_entity.config_entry_id:
continue
# Clear disabled_by if it was disabled by the config entry
if deleted_entity.disabled_by is RegistryEntryDisabler.CONFIG_ENTRY:
disabled_by = None
else:
disabled_by = deleted_entity.disabled_by
# Add a time stamp when the deleted entity became orphaned
self.deleted_entities[key] = attr.evolve(
deleted_entity,
orphaned_timestamp=now_time,
config_entry_id=None,
disabled_by=disabled_by,
deleted_entity, orphaned_timestamp=now_time, config_entry_id=None
)
self.async_schedule_save()

View File

@@ -3368,98 +3368,6 @@ async def test_cleanup_startup(hass: HomeAssistant) -> None:
assert len(mock_call.mock_calls) == 1
async def test_deleted_device_clears_disabled_by_on_config_entry_removal(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test that disabled_by is cleared when config entry is removed."""
config_entry = MockConfigEntry(domain="test", entry_id="mock-id-1")
config_entry.add_to_hass(hass)
# Create a device disabled by the config entry
device = device_registry.async_get_or_create(
config_entry_id="mock-id-1",
identifiers={("test", "device_1")},
name="Test Device",
disabled_by=dr.DeviceEntryDisabler.CONFIG_ENTRY,
)
assert device.config_entries == {"mock-id-1"}
assert device.disabled_by is dr.DeviceEntryDisabler.CONFIG_ENTRY
# Remove the device (it moves to deleted_devices)
device_registry.async_remove_device(device.id)
assert len(device_registry.devices) == 0
assert len(device_registry.deleted_devices) == 1
deleted_device = device_registry.deleted_devices[device.id]
assert deleted_device.config_entries == {"mock-id-1"}
assert deleted_device.disabled_by is dr.DeviceEntryDisabler.CONFIG_ENTRY
assert deleted_device.orphaned_timestamp is None
# Clear the config entry
device_registry.async_clear_config_entry("mock-id-1")
# Verify disabled_by is cleared
deleted_device = device_registry.deleted_devices[device.id]
assert deleted_device.config_entries == set()
assert deleted_device.disabled_by is None # Should be cleared
assert deleted_device.orphaned_timestamp is not None
# Now re-add the config entry and device to verify it can be enabled
config_entry2 = MockConfigEntry(domain="test", entry_id="mock-id-2")
config_entry2.add_to_hass(hass)
# Re-create the device with same identifiers
device2 = device_registry.async_get_or_create(
config_entry_id="mock-id-2",
identifiers={("test", "device_1")},
name="Test Device",
)
assert device2.config_entries == {"mock-id-2"}
assert device2.disabled_by is None # Should not be disabled anymore
assert device2.id == device.id # Should keep the same device id
async def test_deleted_device_disabled_by_user_not_cleared(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
) -> None:
"""Test that disabled_by=USER is not cleared when config entry is removed."""
config_entry = MockConfigEntry(domain="test", entry_id="mock-id-1")
config_entry.add_to_hass(hass)
# Create a device disabled by the user
device = device_registry.async_get_or_create(
config_entry_id="mock-id-1",
identifiers={("test", "device_1")},
name="Test Device",
disabled_by=dr.DeviceEntryDisabler.USER,
)
assert device.config_entries == {"mock-id-1"}
assert device.disabled_by is dr.DeviceEntryDisabler.USER
# Remove the device (it moves to deleted_devices)
device_registry.async_remove_device(device.id)
assert len(device_registry.devices) == 0
assert len(device_registry.deleted_devices) == 1
deleted_device = device_registry.deleted_devices[device.id]
assert deleted_device.config_entries == {"mock-id-1"}
assert deleted_device.disabled_by is dr.DeviceEntryDisabler.USER
assert deleted_device.orphaned_timestamp is None
# Clear the config entry
device_registry.async_clear_config_entry("mock-id-1")
# Verify disabled_by is NOT cleared for USER disabled devices
deleted_device = device_registry.deleted_devices[device.id]
assert deleted_device.config_entries == set()
assert (
deleted_device.disabled_by is dr.DeviceEntryDisabler.USER
) # Should remain USER
assert deleted_device.orphaned_timestamp is not None
@pytest.mark.parametrize("load_registries", [False])
async def test_cleanup_entity_registry_change(
hass: HomeAssistant, mock_config_entry: MockConfigEntry

View File

@@ -782,97 +782,6 @@ async def test_deleted_entity_removing_config_entry_id(
assert entity_registry.deleted_entities[("light", "hue", "1234")] == deleted_entry2
async def test_deleted_entity_clears_disabled_by_on_config_entry_removal(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Test that disabled_by is cleared when config entry is removed."""
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
mock_config.add_to_hass(hass)
# Create an entity disabled by the config entry
entry = entity_registry.async_get_or_create(
"light",
"hue",
"5678",
config_entry=mock_config,
disabled_by=er.RegistryEntryDisabler.CONFIG_ENTRY,
)
assert entry.config_entry_id == "mock-id-1"
assert entry.disabled_by is er.RegistryEntryDisabler.CONFIG_ENTRY
# Remove the entity (it moves to deleted_entities)
entity_registry.async_remove(entry.entity_id)
assert len(entity_registry.entities) == 0
assert len(entity_registry.deleted_entities) == 1
deleted_entry = entity_registry.deleted_entities[("light", "hue", "5678")]
assert deleted_entry.config_entry_id == "mock-id-1"
assert deleted_entry.disabled_by is er.RegistryEntryDisabler.CONFIG_ENTRY
assert deleted_entry.orphaned_timestamp is None
# Clear the config entry
entity_registry.async_clear_config_entry("mock-id-1")
# Verify disabled_by is cleared
deleted_entry = entity_registry.deleted_entities[("light", "hue", "5678")]
assert deleted_entry.config_entry_id is None
assert deleted_entry.disabled_by is None # Should be cleared
assert deleted_entry.orphaned_timestamp is not None
# Now re-add the config entry and entity to verify it can be enabled
mock_config2 = MockConfigEntry(domain="light", entry_id="mock-id-2")
mock_config2.add_to_hass(hass)
# Re-create the entity with same unique ID
entry2 = entity_registry.async_get_or_create(
"light", "hue", "5678", config_entry=mock_config2
)
assert entry2.config_entry_id == "mock-id-2"
assert entry2.disabled_by is None # Should not be disabled anymore
async def test_deleted_entity_disabled_by_user_not_cleared(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Test that disabled_by=USER is not cleared when config entry is removed."""
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
mock_config.add_to_hass(hass)
# Create an entity disabled by the user
entry = entity_registry.async_get_or_create(
"light",
"hue",
"5678",
config_entry=mock_config,
disabled_by=er.RegistryEntryDisabler.USER,
)
assert entry.config_entry_id == "mock-id-1"
assert entry.disabled_by is er.RegistryEntryDisabler.USER
# Remove the entity (it moves to deleted_entities)
entity_registry.async_remove(entry.entity_id)
assert len(entity_registry.entities) == 0
assert len(entity_registry.deleted_entities) == 1
deleted_entry = entity_registry.deleted_entities[("light", "hue", "5678")]
assert deleted_entry.config_entry_id == "mock-id-1"
assert deleted_entry.disabled_by is er.RegistryEntryDisabler.USER
assert deleted_entry.orphaned_timestamp is None
# Clear the config entry
entity_registry.async_clear_config_entry("mock-id-1")
# Verify disabled_by is NOT cleared for USER disabled entities
deleted_entry = entity_registry.deleted_entities[("light", "hue", "5678")]
assert deleted_entry.config_entry_id is None
assert (
deleted_entry.disabled_by is er.RegistryEntryDisabler.USER
) # Should remain USER
assert deleted_entry.orphaned_timestamp is not None
async def test_removing_config_subentry_id(
hass: HomeAssistant, entity_registry: er.EntityRegistry
) -> None: