Skip to content

Rename matter device after commissioning#4515

Draft
bgoncal wants to merge 1 commit intomainfrom
rename-matter-after-comissioning
Draft

Rename matter device after commissioning#4515
bgoncal wants to merge 1 commit intomainfrom
rename-matter-after-comissioning

Conversation

@bgoncal
Copy link
Copy Markdown
Member

@bgoncal bgoncal commented Apr 14, 2026

Summary

Screenshots

Link to pull request in Documentation repository

Documentation: home-assistant/companion.home-assistant#

Any other notes

@bgoncal bgoncal self-assigned this Apr 14, 2026
@bgoncal bgoncal added the matter label Apr 14, 2026
@bgoncal bgoncal marked this pull request as ready for review April 14, 2026 14:13
Copilot AI review requested due to automatic review settings April 14, 2026 14:13
@bgoncal bgoncal marked this pull request as draft April 14, 2026 14:13
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

Adds post-commissioning configuration for Matter devices in the Matter extension by attempting to identify the newly commissioned device and renaming it via Home Assistant’s device registry APIs.

Changes:

  • Capture device registry state before commissioning and use it to identify devices added/updated during commissioning.
  • After commissioning, locate the commissioned Matter device and rename it using a new device-registry update request.
  • Project file updates (path/comment adjustments for some test files and local package reference label changes).

Reviewed changes

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

File Description
Sources/Extensions/Matter/MatterRequestHandler.swift Tracks commissioning context, diffs device registry, identifies a Matter device, and renames it after commissioning.
Sources/Extensions/Matter/HATypedRequest+Matter.swift Adds typed requests/models to list config entries and update a device registry entry name.
HomeAssistant.xcodeproj/project.pbxproj Project metadata updates (file reference comment/path display tweaks and build phase list fields).

Comment on lines +160 to +172
guard let matterDevice = addedDevices.first(where: { device in
isMatterDevice(device, matterConfigEntryIDs: matterConfigEntryIDs)
}) else {
Current.Log.verbose("No Matter device was found among the newly added devices")
return
}

try await renameDevice(
id: matterDevice.id,
to: name,
using: connection
)
Current.Log.info("Renamed commissioned Matter device \(matterDevice.id) to \(name)")
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

configureDevice picks the first device in addedDevices that matches isMatterDevice(...). If multiple Matter devices are added/updated during commissioning (e.g., bridges/multi-endpoint devices or concurrent commissioning), this will rename an arbitrary candidate depending on registry ordering. Consider collecting all matching Matter candidates and only renaming when the match is unambiguous (exactly one), otherwise log and skip (or apply a deterministic selection heuristic, e.g., newest created/modified timestamp).

Suggested change
guard let matterDevice = addedDevices.first(where: { device in
isMatterDevice(device, matterConfigEntryIDs: matterConfigEntryIDs)
}) else {
Current.Log.verbose("No Matter device was found among the newly added devices")
return
}
try await renameDevice(
id: matterDevice.id,
to: name,
using: connection
)
Current.Log.info("Renamed commissioned Matter device \(matterDevice.id) to \(name)")
let matterDevices = addedDevices.filter { device in
isMatterDevice(device, matterConfigEntryIDs: matterConfigEntryIDs)
}
switch matterDevices.count {
case 0:
Current.Log.verbose("No Matter device was found among the newly added devices")
return
case 1:
let matterDevice = matterDevices[0]
try await renameDevice(
id: matterDevice.id,
to: name,
using: connection
)
Current.Log.info("Renamed commissioned Matter device \(matterDevice.id) to \(name)")
default:
Current.Log.warning(
"""
Skipping Matter device rename because multiple Matter candidates were found after commissioning: \
\(matterDevices.map(deviceNameForLogging(_:)))
"""
)
return
}

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +243
let earliestRelevantTimestamp = commissioningStartedAt.timeIntervalSince1970 - 60
return after.filter { device in
max(device.createdAt ?? 0, device.modifiedAt ?? 0) >= earliestRelevantTimestamp
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The timestamp-based fallback in devicesAddedDuringCommissioning can include devices modified long after commissioning started (it filters everything with created/modified >= start-60s). If configureDevice runs later or other devices change during that period, it expands the candidate set and increases the chance of renaming the wrong device. Consider bounding the fallback window (e.g., store a commissioningCompletedAt when the commission call returns and filter within a limited interval) and/or requiring a single unambiguous Matter candidate before renaming.

Copilot uses AI. Check for mistakes.
Comment on lines +178 to +224
private func fetchDeviceRegistry(using connection: HAConnection) async throws -> [DeviceRegistryEntry] {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<[DeviceRegistryEntry], Error>) in
connection.send(.configDeviceRegistryList()).promise.pipe { result in
switch result {
case let .fulfilled(entries):
continuation.resume(returning: entries)
case let .rejected(error):
continuation.resume(throwing: error)
}
}
}
}

private func fetchMatterConfigEntryIDs(using connection: HAConnection) async throws -> Set<String> {
let configEntries = try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<
[MatterConfigEntry],
Error
>) in
connection.send(.configEntriesList()).promise.pipe { result in
switch result {
case let .fulfilled(entries):
continuation.resume(returning: entries)
case let .rejected(error):
continuation.resume(throwing: error)
}
}
}

return Set(configEntries.filter { $0.domain == "matter" }.map(\.entryId))
}

private func renameDevice(
id: String,
to name: String,
using connection: HAConnection
) async throws {
try await withCheckedThrowingContinuation { (continuation: CheckedContinuation<Void, Error>) in
connection.send(.updateDeviceRegistry(deviceId: id, nameByUser: name)).promise.pipe { result in
switch result {
case .fulfilled:
continuation.resume(returning: ())
case let .rejected(error):
continuation.resume(throwing: error)
}
}
}
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

fetchDeviceRegistry, fetchMatterConfigEntryIDs, and renameDevice wrap PromiseKit callbacks in withCheckedThrowingContinuation, but this file already uses PromiseKit’s async() bridge (e.g., in commissionDevice). To reduce boilerplate and avoid continuation misuse (double-resume, leaks on early returns), consider awaiting the underlying Promise directly (e.g., try await connection.send(...).promise.async()).

Copilot uses AI. Check for mistakes.
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 14, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (main@114c738). Learn more about missing BASE report.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4515   +/-   ##
=======================================
  Coverage        ?   42.40%           
=======================================
  Files           ?      274           
  Lines           ?    16316           
  Branches        ?        0           
=======================================
  Hits            ?     6918           
  Misses          ?     9398           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Guide users when they integrate a cover or contact sensor

2 participants