Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
18a0b2f
Adapt ping to new device registry API (#176950)
emontnemery Jul 21, 2026
7891b0e
Update syrupy to 5.5.3 (#176963)
renovate[bot] Jul 21, 2026
f98fa2b
Adapt pglab to new device registry API (#176949)
emontnemery Jul 21, 2026
7f34edf
Adapt bang_olufsen to new device registry API (#176937)
emontnemery Jul 21, 2026
c6a1334
Use registry for Alexa name override (#176926)
arturpragacz Jul 21, 2026
6d387ad
Add port validation to ws http config command (#176876)
edenhaus Jul 21, 2026
cecee55
Adapt airly to new device registry API (#176934)
emontnemery Jul 21, 2026
94334d8
Adapt asuswrt to new device registry API (#176936)
emontnemery Jul 21, 2026
2072d38
Adapt bond to new device registry API (#176938)
emontnemery Jul 21, 2026
1090a17
Adapt daikin to new device registry API (#176939)
emontnemery Jul 21, 2026
4503c83
Adapt habitica to new device registry API (#176944)
emontnemery Jul 21, 2026
b0f82dc
Adapt lutron to new device registry API (#176946)
emontnemery Jul 21, 2026
22143e0
Adapt lutron_caseta to new device registry API (#176947)
emontnemery Jul 21, 2026
dadfe98
Adapt rfxtrx to new device registry API (#176951)
emontnemery Jul 21, 2026
457ba87
Bump yalexs to 9.2.10 (#176929)
jamesshannon Jul 21, 2026
53c4711
Add test-before-configure pylint quality scale checker (#176894)
Markus98 Jul 21, 2026
0111e53
Migrate integrations to async_get_device_by_identifier (part 3) (#176…
emontnemery Jul 21, 2026
93ab898
Add explicit methods for composite devices (#176923)
arturpragacz Jul 21, 2026
bed1390
Add device registry method async_get_devices (#176931)
emontnemery Jul 21, 2026
257b102
Adapt gios to new device registry API (#176943)
emontnemery Jul 21, 2026
dfa4d53
Adapt acmeda to new device registry API (#176933)
emontnemery Jul 21, 2026
811e195
Only detach own config entry on Overkiz device removal (#176898)
iMicknl Jul 21, 2026
589edd6
Fix template test to be cwd-independent (#176815)
karwosts Jul 21, 2026
e562d75
Bump gios to 7.1.1 (#176904)
bieniu Jul 21, 2026
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
4 changes: 3 additions & 1 deletion homeassistant/components/acmeda/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ async def update_devices(

for api_item in api.values():
# Update Device name
device = dev_registry.async_get_device(identifiers={(DOMAIN, api_item.id)})
device = dev_registry.async_get_device_by_identifier(
(DOMAIN, api_item.id), config_entry.entry_id
)
if device is not None:
dev_registry.async_update_device(
device.id,
Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/airly/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: AirlyConfigEntry) -> boo
str(longitude),
),
):
device_entry = device_registry.async_get_device(identifiers={old_ids}) # type: ignore[arg-type]
if device_entry and entry.entry_id in device_entry.config_entries:
device_entry = device_registry.async_get_device_by_identifier(
old_ids, # type: ignore[arg-type]
entry.entry_id,
)
if device_entry:
new_ids = (DOMAIN, f"{latitude}-{longitude}")
device_registry.async_update_device(
device_entry.id, new_identifiers={new_ids}
Expand Down
14 changes: 9 additions & 5 deletions homeassistant/components/alexa/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
__version__,
)
from homeassistant.core import HomeAssistant, State, callback
from homeassistant.helpers import network
from homeassistant.helpers import entity_registry as er, intent, network
from homeassistant.helpers.entity import entity_sources
from homeassistant.util.decorator import Registry

Expand Down Expand Up @@ -283,10 +283,14 @@ def entity_id(self) -> str:

def friendly_name(self) -> str:
"""Return the Alexa API friendly name."""
friendly_name: str = self.entity_conf.get(
CONF_NAME, self.entity.name
).translate(TRANSLATION_TABLE)
return friendly_name
name: str | None = self.entity_conf.get(CONF_NAME)
if name is None:
entity_entry = er.async_get(self.hass).async_get(self.entity_id)
aliases = intent.async_get_entity_aliases(
self.hass, entity_entry, state=self.entity, allow_empty=False
)
name = aliases[0]
return name.translate(TRANSLATION_TABLE)

def description(self) -> str:
"""Return the Alexa API description."""
Expand Down
5 changes: 3 additions & 2 deletions homeassistant/components/asuswrt/diagnostics.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from homeassistant.helpers import device_registry as dr, entity_registry as er

from . import AsusWrtConfigEntry
from .router import get_device_identifier

TO_REDACT = {CONF_PASSWORD, CONF_UNIQUE_ID, CONF_USERNAME}
TO_REDACT_DEV = {ATTR_CONNECTIONS, ATTR_IDENTIFIERS}
Expand All @@ -34,8 +35,8 @@ async def async_get_config_entry_diagnostics(
# Gather information how this AsusWrt device is represented in Home Assistant
device_registry = dr.async_get(hass)
entity_registry = er.async_get(hass)
hass_device = device_registry.async_get_device(
identifiers=router.device_info[ATTR_IDENTIFIERS]
hass_device = device_registry.async_get_device_by_identifier(
get_device_identifier(entry), entry.entry_id
)
if not hass_device:
return data
Expand Down
8 changes: 7 additions & 1 deletion homeassistant/components/asuswrt/router.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@

_LOGGER = logging.getLogger(__name__)


def get_device_identifier(entry: ConfigEntry) -> tuple[str, str]:
"""Return the device registry identifier of the router."""
return (DOMAIN, entry.unique_id or "AsusWRT")


_ENTITY_MIGRATION_ID = {
"sensor_connected_device": "Devices Connected",
"sensor_rx_bytes": "Download",
Expand Down Expand Up @@ -389,7 +395,7 @@ def device_info(self) -> DeviceInfo:
"""Return the device information."""
info = DeviceInfo(
configuration_url=self._api.configuration_url,
identifiers={(DOMAIN, self._entry.unique_id or "AsusWRT")},
identifiers={get_device_identifier(self._entry)},
name=self.host,
model=self._api.model or "Asus Router",
model_id=self._api.model_id,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/august/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@
"integration_type": "hub",
"iot_class": "cloud_push",
"loggers": ["pubnub", "yalexs"],
"requirements": ["yalexs==9.2.7", "yalexs-ble==3.3.1"]
"requirements": ["yalexs==9.2.10", "yalexs-ble==3.3.1"]
}
6 changes: 4 additions & 2 deletions homeassistant/components/bang_olufsen/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@
)


def get_device(hass: HomeAssistant, unique_id: str) -> DeviceEntry:
def get_device(hass: HomeAssistant, unique_id: str, entry_id: str) -> DeviceEntry:
"""Get the device."""
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, unique_id)})
device = device_registry.async_get_device_by_identifier(
(DOMAIN, unique_id), entry_id
)
assert device

return device
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/bang_olufsen/websocket.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def __init__(
BeoBase.__init__(self, entry, client)

self.hass = hass
self._device = get_device(hass, self._unique_id)
self._device = get_device(hass, self._unique_id, self.entry.entry_id)

# WebSocket callbacks
self._client.get_notification_notifications(self.on_notification_notification)
Expand Down
8 changes: 4 additions & 4 deletions homeassistant/components/bond/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ def _async_remove_old_device_identifiers(
) -> None:
"""Remove the non-unique device registry entries."""
for device in hub.devices:
dev = device_registry.async_get_device(identifiers={(DOMAIN, device.device_id)})
if dev is None:
continue
if config_entry_id in dev.config_entries:
dev = device_registry.async_get_device_by_identifier(
(DOMAIN, device.device_id), config_entry_id
)
if dev is not None:
device_registry.async_remove_device(dev.id)


Expand Down
33 changes: 14 additions & 19 deletions homeassistant/components/daikin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,31 +100,26 @@ def _update_unique_id(entity_entry: er.RegistryEntry) -> dict[str, str] | None:
if new_unique_id == old_unique_id:
return

duplicate = dev_reg.async_get_device(
connections={(CONNECTION_NETWORK_MAC, new_mac)}, identifiers=None
duplicate = dev_reg.async_get_device_by_connection(
(CONNECTION_NETWORK_MAC, new_mac), config_entry.entry_id
)

# Remove duplicated device
if duplicate is not None:
if config_entry.entry_id in duplicate.config_entries:
_LOGGER.debug(
"Removing duplicated device %s",
duplicate.name,
)
_LOGGER.debug(
"Removing duplicated device %s",
duplicate.name,
)

# The automatic cleanup in entity registry is scheduled as a task, remove
# the entities manually to avoid unique_id collision when the entities
# are migrated.
duplicate_entities = er.async_entries_for_device(
ent_reg, duplicate.id, True
)
for entity in duplicate_entities:
if entity.config_entry_id == config_entry.entry_id:
ent_reg.async_remove(entity.entity_id)
# The automatic cleanup in entity registry is scheduled as a task, remove
# the entities manually to avoid unique_id collision when the entities
# are migrated.
duplicate_entities = er.async_entries_for_device(ent_reg, duplicate.id, True)
for entity in duplicate_entities:
if entity.config_entry_id == config_entry.entry_id:
ent_reg.async_remove(entity.entity_id)

dev_reg.async_update_device(
duplicate.id, remove_config_entry_id=config_entry.entry_id
)
dev_reg.async_remove_device(duplicate.id)

# Migrate devices
for device_entry in dr.async_entries_for_config_entry(
Expand Down
6 changes: 5 additions & 1 deletion homeassistant/components/edifier_infrared/quality_scale.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ rules:
status: exempt
comment: |
This integration does not store runtime data.
test-before-configure: done
test-before-configure:
status: exempt
comment: |
This integration only proxies commands through an existing infrared
entity, so there is no connection to test in the config flow.
test-before-setup:
status: exempt
comment: |
Expand Down
7 changes: 5 additions & 2 deletions homeassistant/components/gios/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: GiosConfigEntry) -> bool
# We used to use int in device_entry identifiers, convert this to str.
device_registry = dr.async_get(hass)
old_ids = (DOMAIN, station_id)
device_entry = device_registry.async_get_device(identifiers={old_ids}) # type: ignore[arg-type]
if device_entry and entry.entry_id in device_entry.config_entries:
device_entry = device_registry.async_get_device_by_identifier(
old_ids, # type: ignore[arg-type]
entry.entry_id,
)
if device_entry:
new_ids = (DOMAIN, str(station_id))
device_registry.async_update_device(device_entry.id, new_identifiers={new_ids})

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/gios/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "cloud_polling",
"loggers": ["dacite", "gios"],
"quality_scale": "platinum",
"requirements": ["gios==7.1.0"]
"requirements": ["gios==7.1.1"]
}
4 changes: 1 addition & 3 deletions homeassistant/components/habitica/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,7 @@ def _party_update_listener() -> None:
if device := device_reg.async_get_device_by_identifier(
identifier, config_entry.entry_id
):
device_reg.async_update_device(
device.id, remove_config_entry_id=config_entry.entry_id
)
device_reg.async_remove_device(device.id)

notify_entities = [
entry.entity_id
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/heos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ async def async_setup_entry(hass: HomeAssistant, entry: HeosConfigEntry) -> bool

# Create set of identifiers excluding this integration
identifiers = {ident for ident in device.identifiers if ident[0] != DOMAIN}
migrated_identifiers = {(DOMAIN, str(player_id))}
migrated_identifier = (DOMAIN, str(player_id))
# Add migrated if not already present in another
# device, which occurs if the user downgraded and
# then upgraded
if not device_registry.async_get_device(migrated_identifiers):
identifiers.update(migrated_identifiers)
if not device_registry.async_get_devices(identifiers={migrated_identifier}):
identifiers.add(migrated_identifier)
if len(identifiers) > 0:
device_registry.async_update_device(
device.id, new_identifiers=identifiers
Expand Down
6 changes: 4 additions & 2 deletions homeassistant/components/heos/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
class HeosCoordinator(DataUpdateCoordinator[None]):
"""Define the HEOS integration coordinator."""

config_entry: HeosConfigEntry

def __init__(self, hass: HomeAssistant, config_entry: HeosConfigEntry) -> None:
"""Set up the coordinator and set in config_entry."""
credentials: Credentials | None = None
Expand Down Expand Up @@ -208,8 +210,8 @@ def _async_update_player_ids(self, updated_player_ids: dict[int, int]) -> None:
# updated_player_ids contains the mapped IDs in format old:new
for old_id, new_id in updated_player_ids.items():
# update device registry
entry = device_registry.async_get_device(
identifiers={(DOMAIN, str(old_id))}
entry = device_registry.async_get_device_by_identifier(
(DOMAIN, str(old_id)), self.config_entry.entry_id
)
if entry:
new_identifiers = entry.identifiers.copy()
Expand Down
68 changes: 48 additions & 20 deletions homeassistant/components/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,52 @@ async def _async_fallback_config(
return _DEFAULT_CONFIG


def _make_server(
hass: HomeAssistant,
conf: ConfData,
supervisor_unix_socket_path: Path | None = None,
) -> HomeAssistantHTTP:
"""Create a server instance for the given config."""
return HomeAssistantHTTP(
hass,
server_host=conf.get(CONF_SERVER_HOST, _DEFAULT_BIND),
server_port=conf[CONF_SERVER_PORT],
ssl_certificate=conf.get(CONF_SSL_CERTIFICATE),
ssl_peer_certificate=conf.get(CONF_SSL_PEER_CERTIFICATE),
ssl_key=conf.get(CONF_SSL_KEY),
# The loaded config stores trusted proxies as strings
# (JSON-serializable); the forwarded middleware needs
# IPv4Network/IPv6Network objects.
trusted_proxies=[
ip_network(proxy) for proxy in conf.get(CONF_TRUSTED_PROXIES) or []
],
ssl_profile=conf[CONF_SSL_PROFILE],
supervisor_unix_socket_path=supervisor_unix_socket_path,
)


async def async_verify_can_bind(hass: HomeAssistant, conf: ConfData) -> None:
"""Verify a server for ``conf`` can be created and its address bound.

Used to validate a new user-supplied config before it is stored and
applied via a restart; the sockets are released right away. Best effort:
the address can still be taken by another process before the restart, so
the setup fallback chain remains the safety net.

Raises ``HomeAssistantError`` if the SSL configuration is unusable or the
configured address cannot be bound.
"""
server = _make_server(hass, conf)
try:
await server.async_bind()
except OSError as err:
raise HomeAssistantError(
f"Failed to create HTTP server at port {conf[CONF_SERVER_PORT]}: {err}"
) from err
finally:
await server.stop()


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the HTTP API and debug interface."""
# Late import to ensure isal is updated before
Expand Down Expand Up @@ -262,25 +308,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
socket_env,
)

def _make_server(conf: ConfData) -> HomeAssistantHTTP:
return HomeAssistantHTTP(
hass,
server_host=conf.get(CONF_SERVER_HOST, _DEFAULT_BIND),
server_port=conf[CONF_SERVER_PORT],
ssl_certificate=conf.get(CONF_SSL_CERTIFICATE),
ssl_peer_certificate=conf.get(CONF_SSL_PEER_CERTIFICATE),
ssl_key=conf.get(CONF_SSL_KEY),
# The loaded config stores trusted proxies as strings
# (JSON-serializable); the forwarded middleware needs
# IPv4Network/IPv6Network objects.
trusted_proxies=[
ip_network(proxy) for proxy in conf.get(CONF_TRUSTED_PROXIES) or []
],
ssl_profile=conf[CONF_SSL_PROFILE],
supervisor_unix_socket_path=supervisor_unix_socket_path,
)

server = _make_server(conf)
server = _make_server(hass, conf, supervisor_unix_socket_path)
trial_reverted = False
while True:
try:
Expand All @@ -289,7 +317,7 @@ def _make_server(conf: ConfData) -> HomeAssistantHTTP:
store = await async_get_and_load_store(hass)
trial_reverted = store.revert_deadline is not None
conf = await _async_fallback_config(hass, store, conf, err)
server = _make_server(conf)
server = _make_server(hass, conf, supervisor_unix_socket_path)
continue
if trial_reverted:
_LOGGER.warning(
Expand Down
Loading
Loading