Skip to content

Commit 1693299

Browse files
joostlekfrenck
authored andcommitted
Enable disabled Anthropic config entries after entry migration (home-assistant#150098)
1 parent 75200a9 commit 1693299

File tree

3 files changed

+479
-17
lines changed

3 files changed

+479
-17
lines changed

homeassistant/components/anthropic/__init__.py

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,15 @@ async def async_update_options(
8181
async def async_migrate_integration(hass: HomeAssistant) -> None:
8282
"""Migrate integration entry structure."""
8383

84-
entries = hass.config_entries.async_entries(DOMAIN)
84+
# Make sure we get enabled config entries first
85+
entries = sorted(
86+
hass.config_entries.async_entries(DOMAIN),
87+
key=lambda e: e.disabled_by is not None,
88+
)
8589
if not any(entry.version == 1 for entry in entries):
8690
return
8791

88-
api_keys_entries: dict[str, ConfigEntry] = {}
92+
api_keys_entries: dict[str, tuple[ConfigEntry, bool]] = {}
8993
entity_registry = er.async_get(hass)
9094
device_registry = dr.async_get(hass)
9195

@@ -99,30 +103,61 @@ async def async_migrate_integration(hass: HomeAssistant) -> None:
99103
)
100104
if entry.data[CONF_API_KEY] not in api_keys_entries:
101105
use_existing = True
102-
api_keys_entries[entry.data[CONF_API_KEY]] = entry
106+
all_disabled = all(
107+
e.disabled_by is not None
108+
for e in entries
109+
if e.data[CONF_API_KEY] == entry.data[CONF_API_KEY]
110+
)
111+
api_keys_entries[entry.data[CONF_API_KEY]] = (entry, all_disabled)
103112

104-
parent_entry = api_keys_entries[entry.data[CONF_API_KEY]]
113+
parent_entry, all_disabled = api_keys_entries[entry.data[CONF_API_KEY]]
105114

106115
hass.config_entries.async_add_subentry(parent_entry, subentry)
107-
conversation_entity = entity_registry.async_get_entity_id(
116+
conversation_entity_id = entity_registry.async_get_entity_id(
108117
"conversation",
109118
DOMAIN,
110119
entry.entry_id,
111120
)
112-
if conversation_entity is not None:
121+
device = device_registry.async_get_device(
122+
identifiers={(DOMAIN, entry.entry_id)}
123+
)
124+
125+
if conversation_entity_id is not None:
126+
conversation_entity_entry = entity_registry.entities[conversation_entity_id]
127+
entity_disabled_by = conversation_entity_entry.disabled_by
128+
if (
129+
entity_disabled_by is er.RegistryEntryDisabler.CONFIG_ENTRY
130+
and not all_disabled
131+
):
132+
# Device and entity registries don't update the disabled_by flag
133+
# when moving a device or entity from one config entry to another,
134+
# so we need to do it manually.
135+
entity_disabled_by = (
136+
er.RegistryEntryDisabler.DEVICE
137+
if device
138+
else er.RegistryEntryDisabler.USER
139+
)
113140
entity_registry.async_update_entity(
114-
conversation_entity,
141+
conversation_entity_id,
115142
config_entry_id=parent_entry.entry_id,
116143
config_subentry_id=subentry.subentry_id,
144+
disabled_by=entity_disabled_by,
117145
new_unique_id=subentry.subentry_id,
118146
)
119147

120-
device = device_registry.async_get_device(
121-
identifiers={(DOMAIN, entry.entry_id)}
122-
)
123148
if device is not None:
149+
# Device and entity registries don't update the disabled_by flag when
150+
# moving a device or entity from one config entry to another, so we
151+
# need to do it manually.
152+
device_disabled_by = device.disabled_by
153+
if (
154+
device.disabled_by is dr.DeviceEntryDisabler.CONFIG_ENTRY
155+
and not all_disabled
156+
):
157+
device_disabled_by = dr.DeviceEntryDisabler.USER
124158
device_registry.async_update_device(
125159
device.id,
160+
disabled_by=device_disabled_by,
126161
new_identifiers={(DOMAIN, subentry.subentry_id)},
127162
add_config_subentry_id=subentry.subentry_id,
128163
add_config_entry_id=parent_entry.entry_id,
@@ -147,7 +182,7 @@ async def async_migrate_integration(hass: HomeAssistant) -> None:
147182
title=DEFAULT_CONVERSATION_NAME,
148183
options={},
149184
version=2,
150-
minor_version=2,
185+
minor_version=3,
151186
)
152187

153188

@@ -173,6 +208,38 @@ async def async_migrate_entry(hass: HomeAssistant, entry: AnthropicConfigEntry)
173208

174209
hass.config_entries.async_update_entry(entry, minor_version=2)
175210

211+
if entry.version == 2 and entry.minor_version == 2:
212+
# Fix migration where the disabled_by flag was not set correctly.
213+
# We can currently only correct this for enabled config entries,
214+
# because migration does not run for disabled config entries. This
215+
# is asserted in tests, and if that behavior is changed, we should
216+
# correct also disabled config entries.
217+
device_registry = dr.async_get(hass)
218+
entity_registry = er.async_get(hass)
219+
devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id)
220+
entity_entries = er.async_entries_for_config_entry(
221+
entity_registry, entry.entry_id
222+
)
223+
if entry.disabled_by is None:
224+
# If the config entry is not disabled, we need to set the disabled_by
225+
# flag on devices to USER, and on entities to DEVICE, if they are set
226+
# to CONFIG_ENTRY.
227+
for device in devices:
228+
if device.disabled_by is not dr.DeviceEntryDisabler.CONFIG_ENTRY:
229+
continue
230+
device_registry.async_update_device(
231+
device.id,
232+
disabled_by=dr.DeviceEntryDisabler.USER,
233+
)
234+
for entity in entity_entries:
235+
if entity.disabled_by is not er.RegistryEntryDisabler.CONFIG_ENTRY:
236+
continue
237+
entity_registry.async_update_entity(
238+
entity.entity_id,
239+
disabled_by=er.RegistryEntryDisabler.DEVICE,
240+
)
241+
hass.config_entries.async_update_entry(entry, minor_version=3)
242+
176243
LOGGER.debug(
177244
"Migration to version %s:%s successful", entry.version, entry.minor_version
178245
)

homeassistant/components/anthropic/config_flow.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class AnthropicConfigFlow(ConfigFlow, domain=DOMAIN):
7575
"""Handle a config flow for Anthropic."""
7676

7777
VERSION = 2
78-
MINOR_VERSION = 2
78+
MINOR_VERSION = 3
7979

8080
async def async_step_user(
8181
self, user_input: dict[str, Any] | None = None

0 commit comments

Comments
 (0)