Skip to content

Matter: Add option to synchronise HA device names to Matter NodeLabel#169844

Open
markvp wants to merge 3 commits intohome-assistant:devfrom
markvp:matter-sync-names
Open

Matter: Add option to synchronise HA device names to Matter NodeLabel#169844
markvp wants to merge 3 commits intohome-assistant:devfrom
markvp:matter-sync-names

Conversation

@markvp
Copy link
Copy Markdown

@markvp markvp commented May 5, 2026

Proposed change

Adds a per-config-entry option (under Configure on the Matter integration card) that, when enabled, pushes Home Assistant device renames to the corresponding Matter device's NodeLabel attribute.

Behaviour:

  • One-way: HA → Matter only. NodeLabel changes on the Matter side are not reflected back into HA.
  • Bridged endpoints: writes BridgedDeviceBasicInformation.NodeLabel on the bridged endpoint.
  • Root nodes: writes BasicInformation.NodeLabel on endpoint 0.
  • Names are truncated to 32 UTF-8 bytes (Matter spec limit), with partial trailing multi-byte sequences dropped cleanly.
  • Toggling the option on (or having it on at setup) triggers a one-shot backfill so existing HA names propagate immediately.
  • Listener fires only on name_by_user changes; clearing an override falls back to the inferred device name so the Matter side is not left stale.

The existing get_endpoint_from_device_entry helper now takes the MatterClient directly so resolution works during the entry's setup phase, before it transitions to LOADED.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request:
  • Link to developer documentation pull request:
  • Link to frontend pull request:

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (`ruff format homeassistant tests`)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: `python3 -m script.hassfest`.
  • New or updated dependencies have been added to `requirements_all.txt`.
    Updated by running `python3 -m script.gen_requirements_all`.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings May 5, 2026 13:36
@markvp markvp requested a review from a team as a code owner May 5, 2026 13:36
@home-assistant home-assistant Bot added cla-signed has-tests integration: matter new-feature Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage Top 50 Integration is ranked within the top 50 by usage Quality Scale: No score labels May 5, 2026
@home-assistant
Copy link
Copy Markdown
Contributor

home-assistant Bot commented May 5, 2026

Hey there @home-assistant/matter, mind taking a look at this pull request as it has been labeled with an integration (matter) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of matter can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant mark-draft Mark the pull request as draft.
  • @home-assistant ready-for-review Remove the draft status from the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign matter Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant update-branch Update the pull request branch with the base branch.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an optional, per-config-entry feature to the Matter integration that synchronizes Home Assistant device renames to the corresponding Matter NodeLabel attribute (HA → Matter only).

Changes:

  • Add a Matter options flow setting (sync_names) to enable/disable one-way device name synchronization.
  • Listen for device registry name_by_user updates and write the appropriate Matter NodeLabel attribute (root vs bridged endpoints), including a one-shot backfill when enabled.
  • Add test coverage for rename behavior, bridged/root writes, truncation, backfill, and options flow persistence.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
homeassistant/components/matter/__init__.py Adds name-sync listener, NodeLabel writing logic, and backfill behavior.
homeassistant/components/matter/config_flow.py Implements an options flow to toggle sync_names.
homeassistant/components/matter/const.py Introduces CONF_SYNC_NAMES and NODE_LABEL_MAX_BYTES.
homeassistant/components/matter/helpers.py Adds endpoint resolution helper used by name sync and backfill.
homeassistant/components/matter/strings.json Adds user-facing options flow strings for the new setting.
tests/components/matter/test_name_sync.py Adds tests for HA→Matter name synchronization behavior.
tests/components/matter/test_config_flow.py Adds tests ensuring options flow persists the submitted value.

Comment thread homeassistant/components/matter/helpers.py Outdated
Comment on lines +157 to +165
return next(
(
endpoint
for node in matter_client.get_nodes()
for endpoint in node.endpoints.values()
if get_device_id(server_info, endpoint) == device_id
),
None,
)
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not changing for now. A typical Matter fabric is on the order of tens of nodes, the device-rename path is user-driven (one event per click), and the existing get_node_from_device_entry uses the same O(N) scan. Adding a separate cache would mean keeping it in sync with node add/remove events; happy to revisit if a real fabric demonstrates the cost.

Comment on lines +290 to +300
matter_client = entry.runtime_data.adapter.matter_client
devices = dr.async_entries_for_config_entry(dr.async_get(hass), entry.entry_id)
for device in devices:
endpoint = get_endpoint_from_device_entry(matter_client, device)
if endpoint is None:
continue
label = _resolve_label(device)
if label is None:
continue
await _async_write_node_label(matter_client, endpoint, label)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sequential is intentional. Backfill is a one-shot event (toggle-on or setup-with-option-already-on), and Thread devices in particular don't react well to bursts of concurrent writes — sequential keeps it polite to the fabric. Cost is bounded by fabric size, which is small in practice.

markvp and others added 2 commits May 6, 2026 12:14
Add a per-config-entry option that, when enabled, pushes Home Assistant
device renames to the corresponding Matter device's NodeLabel attribute.
Sync is one-way (HA → Matter): NodeLabel changes on the Matter side are
not reflected back. Bridged endpoints write BridgedDeviceBasicInformation
NodeLabel on the bridged endpoint; root nodes write BasicInformation
NodeLabel on endpoint 0. Names are truncated to 32 UTF-8 bytes per spec.

Toggling the option on (or having it on at setup) triggers a one-shot
backfill of the current HA names to every Matter device for the entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lstrip() removes a character set, not a prefix; switch to removeprefix()
in get_endpoint_from_device_entry. Safe by accident today (device IDs
are hex+dash, no overlap with the "deviceid_" character set), but the
right primitive for "strip this prefix once".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@markvp markvp force-pushed the matter-sync-names branch from b78527c to f65f35f Compare May 6, 2026 12:14
Copilot AI review requested due to automatic review settings May 6, 2026 12:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment on lines +219 to +223
except MatterError as err:
LOGGER.debug(
"Failed to sync NodeLabel for node %s endpoint %s: %s",
endpoint.node.node_id,
endpoint.endpoint_id,
Comment on lines +159 to +162
endpoint
for node in matter_client.get_nodes()
for endpoint in node.endpoints.values()
if get_device_id(server_info, endpoint) == device_id
"step": {
"init": {
"data": {
"sync_names": "Synchronise device names to Matter (one-way)"
Comment on lines +191 to +195
encoded = name.encode("utf-8")
if len(encoded) <= NODE_LABEL_MAX_BYTES:
return name
# Decode back, dropping a partial trailing multi-byte sequence if any.
return encoded[:NODE_LABEL_MAX_BYTES].decode("utf-8", errors="ignore")
- Fix lstrip → removeprefix in get_node_from_device_entry
- Return compose-parent endpoint from get_endpoint_from_device_entry
- Catch NotConnected in _async_write_node_label
- Fix spelling: Synchronise → Synchronize
- Add multibyte UTF-8 truncation test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed has-tests integration: matter new-feature Quality Scale: No score Top 50 Integration is ranked within the top 50 by usage Top 100 Integration is ranked within the top 100 by usage Top 200 Integration is ranked within the top 200 by usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants