Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/aprilaire/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: AprilaireConfigEntry) ->
host = entry.data[CONF_HOST]
port = entry.data[CONF_PORT]

coordinator = AprilaireCoordinator(hass, entry.unique_id, host, port)
coordinator = AprilaireCoordinator(hass, entry, host, port)
await coordinator.start_listen()

async def ready_callback(ready: bool) -> None:
Expand Down
12 changes: 8 additions & 4 deletions homeassistant/components/aprilaire/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ class AprilaireCoordinator(BaseDataUpdateCoordinatorProtocol):
def __init__(
self,
hass: HomeAssistant,
unique_id: str | None,
config_entry: AprilaireConfigEntry | None,
host: str,
port: int,
) -> None:
"""Initialize the coordinator."""

self.hass = hass
self.unique_id = unique_id
self.config_entry = config_entry
self.unique_id = config_entry.unique_id if config_entry else None
self.data: dict[str, Any] = {}

self._listeners: dict[CALLBACK_TYPE, tuple[CALLBACK_TYPE, object | None]] = {}
Expand Down Expand Up @@ -88,13 +89,16 @@ def async_set_updated_data(self, data: Any) -> None:
new_device_info = self.create_device_info(data)

if (
old_device_info is not None
self.config_entry is not None
and old_device_info is not None
and new_device_info is not None
and old_device_info != new_device_info
):
device_registry = dr.async_get(self.hass)

device = device_registry.async_get_device(old_device_info["identifiers"])
device = device_registry.async_get_device_by_identifier(
next(iter(old_device_info["identifiers"])), self.config_entry.entry_id
)

if device is not None:
new_device_info.pop("identifiers", None)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/assist_satellite/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/assist_satellite",
"integration_type": "entity",
"quality_scale": "internal",
"requirements": ["hassil==3.8.0"]
"requirements": ["hassil==3.10.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/conversation/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/conversation",
"integration_type": "entity",
"quality_scale": "internal",
"requirements": ["hassil==3.8.0", "home-assistant-intents==2026.6.24"]
"requirements": ["hassil==3.10.0", "home-assistant-intents==2026.6.24"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/infrared/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
"documentation": "https://www.home-assistant.io/integrations/infrared",
"integration_type": "entity",
"quality_scale": "internal",
"requirements": ["infrared-protocols==8.1.0"]
"requirements": ["infrared-protocols==8.2.0"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/izone/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@
"integration_type": "hub",
"iot_class": "local_polling",
"loggers": ["pizone"],
"requirements": ["python-izone==1.3.6"]
"requirements": ["python-izone==1.3.7"]
}
2 changes: 1 addition & 1 deletion homeassistant/components/template/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass,
helper_config_entry_id=entry.entry_id,
source_device_id=entry.options.get(CONF_DEVICE_ID),
sweep_helper_devices=True,
remove_all_devices=True,
)

for key in (CONF_MAX, CONF_MIN, CONF_STEP):
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/helpers/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ def async_remove_stale_devices_links_keep_entity_device(
Deprecated, does nothing: a device belongs to a single config entry, so a helper no
longer adds its config entry to the source device and there is no stale config entry
link to remove. Call helper_integration.async_remove_helper_devices with
sweep_helper_devices=True to remove devices a helper created for previously selected
remove_all_devices=True to remove devices a helper created for previously selected
source devices.
"""
report_usage(
"calls async_remove_stale_devices_links_keep_entity_device, which is deprecated "
"and does nothing: a device belongs to a single config entry, so a helper no "
"longer adds its config entry to the source device. Call "
"homeassistant.helpers.helper_integration.async_remove_helper_devices with "
"sweep_helper_devices=True instead",
"remove_all_devices=True instead",
core_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2027.8.0",
)
Expand All @@ -112,15 +112,15 @@ def async_remove_stale_devices_links_keep_current_device(
Deprecated, does nothing: a device belongs to a single config entry, so a helper no
longer adds its config entry to another device and there is no stale config entry link
to remove. Call helper_integration.async_remove_helper_devices with
sweep_helper_devices=True to remove devices a helper created for previously selected
remove_all_devices=True to remove devices a helper created for previously selected
source devices.
"""
report_usage(
"calls async_remove_stale_devices_links_keep_current_device, which is deprecated "
"and does nothing: a device belongs to a single config entry, so a helper no "
"longer adds its config entry to another device. Call "
"homeassistant.helpers.helper_integration.async_remove_helper_devices with "
"sweep_helper_devices=True instead",
"remove_all_devices=True instead",
core_behavior=ReportBehavior.LOG,
breaks_in_ha_version="2027.8.0",
)
16 changes: 8 additions & 8 deletions homeassistant/helpers/helper_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def async_remove_helper_devices(
*,
helper_config_entry_id: str,
source_device_id: str | None,
sweep_helper_devices: bool = False,
remove_all_devices: bool = False,
keep_device_ids: Collection[str] = (),
) -> None:
"""Migrate a helper which has tried to own a device instead of just linking to it.
Expand All @@ -154,15 +154,15 @@ def async_remove_helper_devices(
device relinks the entities to it. A pre-migration composite id and None have no
concrete device to hold the link, so the entities are detached; in targeted mode
a composite or None source with no matching duplicate is a no-op.
:param sweep_helper_devices: By default only the helper's single duplicate of
:param remove_all_devices: By default only the helper's single duplicate of
source_device_id (a split or fork) is removed. When True, every device the
helper owns except source_device_id and keep_device_ids is removed instead -
even when source_device_id no longer exists, in which case the helper's
entities are left without a device. Use this to clean up devices the helper
created but never removed itself, such as a fork left behind for each
previously selected source device.
:param keep_device_ids: Devices the helper legitimately owns which must not be removed.
Only consulted when sweep_helper_devices is True.
Only consulted when remove_all_devices is True.
"""
device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
Expand All @@ -173,10 +173,10 @@ def async_remove_helper_devices(
else None
)
if source_device is None:
# No source device (gone, or none selected). In sweep mode the helper's devices are
# still removed, leaving its entities without a device; targeted mode has no duplicate
# to match.
if sweep_helper_devices:
# No source device (gone, or none selected). In remove-all mode the helper's devices
# are still removed, leaving its entities without a device; targeted mode has no
# duplicate to match.
if remove_all_devices:
_sweep_helper_devices(
device_registry,
entity_registry,
Expand All @@ -195,7 +195,7 @@ def async_remove_helper_devices(
)
target_device_id = source_device_id if source_is_concrete else None

if sweep_helper_devices:
if remove_all_devices:
_sweep_helper_devices(
device_registry,
entity_registry,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ go2rtc-client==0.4.0
ha-ffmpeg==3.2.2
habluetooth==6.26.5
hass-nabucasa==2.2.0
hassil==3.8.0
hassil==3.10.0
home-assistant-bluetooth==2.0.0
home-assistant-frontend==20260624.6
home-assistant-intents==2026.6.24
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions requirements_all.txt

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions tests/helpers/test_helper_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ async def test_async_remove_helper_devices_sweep(

A helper that forked a device for each source it linked to, without removing the
old forks, accumulates stale devices that don't match the current source (so the
targeted match never sees them). sweep_helper_devices removes them and relinks the
targeted match never sees them). remove_all_devices removes them and relinks the
helper's entities - including a stranded, device-less one - to the source, while
keep_device_ids and the source device are preserved.
"""
Expand Down Expand Up @@ -737,7 +737,7 @@ async def test_async_remove_helper_devices_sweep(
hass,
helper_config_entry_id=helper_config_entry.entry_id,
source_device_id=source_device.id,
sweep_helper_devices=True,
remove_all_devices=True,
keep_device_ids={kept_device.id},
)

Expand Down Expand Up @@ -796,7 +796,7 @@ async def test_async_remove_helper_devices_sweep_no_source(
hass,
helper_config_entry_id=helper_config_entry.entry_id,
source_device_id=source_device_id,
sweep_helper_devices=True,
remove_all_devices=True,
)

# The helper's device is removed and its entity left without a device
Expand All @@ -811,7 +811,7 @@ async def test_async_remove_helper_devices_none_source_targeted_noop(
) -> None:
"""Targeted mode is a no-op when no source device is selected.

Without sweep_helper_devices there is no duplicate to match against a missing source, so
Without remove_all_devices there is no duplicate to match against a missing source, so
the helper's device and its entity's device link are left untouched.
"""
helper_config_entry = MockConfigEntry(domain=HELPER_DOMAIN)
Expand Down
Loading