CarPlay-Aware Assist Triggering#4496
Conversation
There was a problem hiding this comment.
Hi @lowlyocean
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
ba1d197 to
2e86c8c
Compare
There was a problem hiding this comment.
Hi @lowlyocean
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
|
|
Can you attach a screen recording demonstrating the feature? |
|
Unfortunately I don't own a Mac to actually run XCode & CarPlay simulator. This PR was prepared with OpenCode + Unsloth's gemma-4-26B-A4B-it-UD-Q3_K_M. |
|
When opening PRs to the Open Home Foundation repos it is a requirement that all code has been tested (manually as well) and the contributor understands it's implementation when created by a LLM. I cannot approve this PR otherwise, but if you don't have access to a mac right now I will reserve sometime to try it myself since it is a feature that I see value, I'm just a bit worried that this goes against Apple's rules, it explicity says that AI/Voice assistant CarPlay apps need to have single purpose and can't present any other UI that is not focused on that task, since we already have a CarPlay app providing different features, this can become an issue. |
|
Yes, I appreciate that this PR may need to be closed in its current form. I wanted this feature (as an end user) sufficiently that I found it worthwhile to at least try to offer some starting point to someone that does have Apple dev access & better familiarity with the codebase. Thank you for testing it locally when you have some time I did not know Apple had a rule along those lines. I might suggest that if we consider Assist widget on its own, than it would comply with such guardrails. In other words, no direct navigation from the Assist scene back to the main HA scene (or vice versa). WDYT? |
|
To be honest, this is very new, so it will depend on Apple's review team, nevertheless, we should try |
There was a problem hiding this comment.
Hi @lowlyocean
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
I had to tweak a lot to make it compile, main...carplay_assist At this point I would prefer closing the PR and starting from scratch to be honest |
Summary
Enables the Assist widget to trigger voice recording functionality within the CarPlay interface using a "Signal/Observe" pattern via
NSUserActivity. The implementation ensures that the intent remains functional for mobile users by correctly targeting the main web view scene when a CarPlay session is not present.High-Level Overview
The Problem
Users want to trigger the "Assist" feature (voice interaction with Home Assistant) directly from a Home Assistant widget on their iPhone lock screen. Currently, when a user interacts with the widget, the app needs to decide where to show the Assist interface: on the phone's main screen (the web view) or on the car's display (CarPlay). Without a way to distinguish between these two, the app might try to open a mobile popup while the user is driving, which is not only useless but potentially distracting.
The Solution
We implemented a "smart trigger" system. When the widget is pressed, the app now checks: "Is the user currently using CarPlay?"
Architectural Overview
We moved from a "one-size-fits-all" intent to a Signal/Observe pattern. Instead of the widget telling the app exactly what to do, it now sends a signal with a payload, and the relevant part of the app observes that signal and decides how to react based on the current context.
Workflow:
AssistAppIntentchecks if a CarPlay scene is active.webViewWindowControllerPromiseto callshowAssistdirectly on the mobileWebViewExternalMessageHandler.activateAnySceneto send anNSUserActivitywith auserInfopayload.CarPlaySceneDelegateintercepts theNSUserActivity, extracts the payload, and presents theCarPlayAssistTemplate.Technical Implementation Details
1. Intent Logic (
AssistAppIntent)The
AppIntentperforms a context check using theSceneManager.Current.sceneManager.webViewWindowControllerPromise.then(\.webViewControllerPromise)to invoke theshowAssistmethod.Current.sceneManager.activateAnyScene(for: .assist, with: userInfo)whereuserInfocontainspipelineId,serverId, andwithVoice.2. CarPlay Signaling (
CarPlaySceneDelegate)The
CarPlaySceneDelegateimplementsCPTemplateApplicationSceneDelegate. It monitors theuserActivityof the connecting scene:.assistactivityType.userInfopayload.presentAssistTemplate(...), which instantiates a newAssistViewModelspecifically for the CarPlay session.3. State-Driven UI (
CarPlayAssistTemplate)To comply with CarPlay's strict UI requirements, we implemented a
CarPlayTemplateProvider.mapViewModelToState(_:)function translates theAssistViewModelstates into a simplifiedCarPlayAssistStateenum (.idle,.listening,.thinking,.speaking).SFSafeSymbolsto map these states to appropriate system icons (e.g.,.waveformfor listening,.ellipsisfor thinking,.speakerfor speaking) within aCPListItem.4. Data Flow & Synchronization
AssistViewModel.@MainActorto ensure all UI updates occur on the main thread, preventing race conditions during rapid state changes.