Remove template config entry from source device (#157814)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
Erik Montnemery
2025-12-03 15:24:48 +01:00
committed by GitHub
co-authored by Martin Hjelmare
parent ceb13e70b9
commit e009898107
3 changed files with 120 additions and 0 deletions
@@ -28,6 +28,9 @@ from homeassistant.helpers import discovery, issue_registry as ir
from homeassistant.helpers.device import (
async_remove_stale_devices_links_keep_current_device,
)
from homeassistant.helpers.helper_integration import (
async_remove_helper_config_entry_from_source_device,
)
from homeassistant.helpers.reload import async_reload_integration_platforms
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType
@@ -116,6 +119,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up a config entry."""
# This can be removed in HA Core 2026.7
async_remove_stale_devices_links_keep_current_device(
hass,
entry.entry_id,
@@ -154,6 +158,41 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
"""Migrate old entry."""
_LOGGER.debug(
"Migrating configuration from version %s.%s",
config_entry.version,
config_entry.minor_version,
)
if config_entry.version > 1:
# This means the user has downgraded from a future version
return False
if config_entry.version == 1:
if config_entry.minor_version < 2:
# Remove the template config entry from the source device
if source_device_id := config_entry.options.get(CONF_DEVICE_ID):
async_remove_helper_config_entry_from_source_device(
hass,
helper_config_entry_id=config_entry.entry_id,
source_device_id=source_device_id,
)
hass.config_entries.async_update_entry(
config_entry, version=1, minor_version=2
)
_LOGGER.debug(
"Migration to configuration version %s.%s successful",
config_entry.version,
config_entry.minor_version,
)
return True
async def _process_config(hass: HomeAssistant, hass_config: ConfigType) -> None:
"""Process config."""
coordinators = hass.data.pop(DATA_COORDINATORS, None)
@@ -697,6 +697,9 @@ class TemplateConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
options_flow = OPTIONS_FLOW
options_flow_reloads = True
MINOR_VERSION = 2
VERSION = 1
@callback
def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
"""Return config entry title."""
+78
View File
@@ -8,6 +8,7 @@ import pytest
from homeassistant import config
from homeassistant.components import labs
from homeassistant.components.template import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import SERVICE_RELOAD
from homeassistant.core import Context, HomeAssistant
from homeassistant.helpers import (
@@ -754,3 +755,80 @@ async def test_config_entry_reload_when_labs_flag_changes(
assert hass.states.get("sensor.hello") is not None
assert hass.states.get("sensor.hello").state == set_state
async def test_migration_1_1(
hass: HomeAssistant,
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test migration from v1.1 removes template config entry from device."""
device_config_entry = MockConfigEntry()
device_config_entry.add_to_hass(hass)
device_entry = device_registry.async_get_or_create(
config_entry_id=device_config_entry.entry_id,
identifiers={("test", "identifier_test")},
connections={("mac", "30:31:32:33:34:35")},
)
template_config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
"name": "My template",
"template_type": "sensor",
"state": "{{ 'foo' }}",
"device_id": device_entry.id,
},
title="My template",
version=1,
minor_version=1,
)
template_config_entry.add_to_hass(hass)
# Add the helper config entry to the device
device_registry.async_update_device(
device_entry.id, add_config_entry_id=template_config_entry.entry_id
)
# Check preconditions
device_entry = device_registry.async_get(device_entry.id)
assert template_config_entry.entry_id in device_entry.config_entries
await hass.config_entries.async_setup(template_config_entry.entry_id)
await hass.async_block_till_done()
assert template_config_entry.state is ConfigEntryState.LOADED
# Check that the helper config entry is removed from the device and the helper
# entity is linked to the source device
device_entry = device_registry.async_get(device_entry.id)
assert template_config_entry.entry_id not in device_entry.config_entries
template_entity_entry = entity_registry.async_get("sensor.my_template")
assert template_entity_entry.device_id == device_entry.id
assert template_config_entry.version == 1
assert template_config_entry.minor_version == 2
async def test_migration_from_future_version(
hass: HomeAssistant,
) -> None:
"""Test migration from future version."""
config_entry = MockConfigEntry(
data={},
domain=DOMAIN,
options={
"name": "hello",
"template_type": "sensor",
"state": "{{ 'foo' }}",
},
title="My template",
version=2,
minor_version=1,
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.MIGRATION_ERROR