Communicate to frontend when matter commissioning finishes#4684
Open
bgoncal wants to merge 3 commits into
Open
Communicate to frontend when matter commissioning finishes#4684bgoncal wants to merge 3 commits into
bgoncal wants to merge 3 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR extends the WKWebView “external bus” integration to notify the Home Assistant frontend when the native Apple Matter commissioning flow completes, and (when available) includes the user-selected device name captured from the Matter extension.
Changes:
- Add a new outgoing external bus command (
matter/commission/finish) and corresponding unit test coverage. - Persist the commissioned device name from the Matter extension and return it from
Current.matter.commission. - Send the completion command to the frontend from
WebViewExternalMessageHandlerafter commissioning completes. - Add a large standalone document for debugging Live Activities locally (currently not mentioned in the PR summary).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/App/WebView/WebViewExternalMessageHandlerTests.swift | Adds a test verifying a finish bus command is sent with the commissioned device name. |
| Tests/App/WebView/WebViewExternalBusMessageTests.swift | Updates outgoing message key coverage and allCases count for the new command. |
| Tests/App/WebView/Mocks/MockWebViewController.swift | Adds an XCTestExpectation hook to assert JS evaluation was triggered. |
| Sources/Shared/Settings/SettingsStore.swift | Adds shared storage for the last commissioned Matter device name. |
| Sources/Shared/Environment/MatterWrapper.swift | Changes commission to return an optional device name and reads/clears it after commissioning. |
| Sources/Extensions/Matter/MatterRequestHandler.swift | Captures the device name via configureDevice(named:in:) for later retrieval by the app. |
| Sources/App/Frontend/ExternalMessageBus/WebViewExternalMessageHandler.swift | Sends the new matter/commission/finish command to the frontend after commissioning. |
| Sources/App/Frontend/ExternalMessageBus/WebViewExternalBusMessage.swift | Adds matterCommissionFinish to the outgoing message enum. |
| debug-live-activities-locally.md | Adds a detailed Live Activities local debugging guide (scope currently unrelated to Matter commissioning). |
Comments suppressed due to low confidence (2)
Sources/App/Frontend/ExternalMessageBus/WebViewExternalMessageHandler.swift:489
matter/commission/finishis only sent when a non-nil device name is returned. This means the frontend may never be notified that commissioning finished on OS versions where Matter commissioning returnsnil, or if the user closes the Apple flow without setting a name. Consider always sending the finish command, and include the name only when available; also consider sending the finish command from thecatchpath since this flow can surface as an error (e.g., cancellation) even when pairing succeeds.
Current.matter.commission(webViewController.server).done { [weak self] deviceName in
Current.Log.info("Commission call completed with device name: \(String(describing: deviceName))")
guard let deviceName else {
Current.Log.error("Matter commission completed without a device name")
return
}
self?.sendExternalBus(message: .init(
command: WebViewExternalBusOutgoingMessage.matterCommissionFinish.rawValue,
payload: ["name": deviceName]
))
}.catch { [weak self] error in
// we don't show a user-visible error because even a successful operation will return 'cancelled'
// but the errors aren't public, so we can't compare -- the apple ui shows errors visually though
Current.Log.error(error)
self?.webViewController?.refresh()
}
Sources/Shared/Environment/MatterWrapper.swift:79
- If
MatterAddDeviceRequest.perform()throws after the extension has already provided a device name,matterLastCommissionedDeviceNameis never cleared. Since this value is stored in shared persistent storage, it can linger longer than intended and be read by a later successful run. Clear the stored name in the error path as well.
try await request.perform()
let deviceName = Current.settingsStore.matterLastCommissionedDeviceName
// Reset device name after reading it, so that if the user tries to pair another device without
// going through the flow again, we won't have a stale name hanging around
Current.settingsStore.matterLastCommissionedDeviceName = nil
Current.Log.info("Matter pairing finished (native flow manually closed or pairing succeeded)")
seal.fulfill(deviceName)
} catch {
Current.Log.error("Matter pairing failed: \(error)")
seal.reject(error)
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Screenshots
Link to pull request in Documentation repository
Documentation: home-assistant/companion.home-assistant#
Any other notes