Skip to content

Enable search by entity ID and area name in HAAppEntityAppIntentEntity#4075

Merged
bgoncal merged 3 commits intomainfrom
copilot/add-search-matching-for-entities
Dec 10, 2025
Merged

Enable search by entity ID and area name in HAAppEntityAppIntentEntity#4075
bgoncal merged 3 commits intomainfrom
copilot/add-search-matching-for-entities

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Dec 10, 2025

Summary

Extended entity search in App Intents to match against entity ID and area name in addition to entity display name.

Modified: HAAppEntityAppIntentEntityQuery.entities(matching:)

  • Added case-insensitive matching on entityId
  • Added case-insensitive matching on area (with nil-safe handling)
  • Combined with existing displayString match using OR logic

Users can now search entities by:

  • Display name: "Living Room Light"
  • Entity ID: "light.living_room"
  • Area: "Living Room"

Screenshots

N/A - Backend search logic change only

Link to pull request in Documentation repository

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

Any other notes

None

Original prompt

When searching HAAppEntityAppIntentEntity, allow matching name, entity id and area name


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com>
Copilot AI changed the title [WIP] Add entity search matching by name, id, and area Enable search by entity ID and area name in HAAppEntityAppIntentEntity Dec 10, 2025
Copilot AI requested a review from bgoncal December 10, 2025 15:35
Updated the entity filtering logic to use case-insensitive and diacritic-insensitive matching for display string, entity ID, and area name. This enhances the search experience by making it more robust to user input variations.
@bgoncal bgoncal marked this pull request as ready for review December 10, 2025 15:59
Copilot AI review requested due to automatic review settings December 10, 2025 15:59
@bgoncal bgoncal enabled auto-merge (squash) December 10, 2025 15:59
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 enhances the entity search functionality in App Intents by expanding search capabilities from just entity display names to include entity IDs and area names. This makes it easier for users to find entities using multiple search criteria, improving the overall user experience when working with App Intents and Shortcuts.

Key Changes:

  • Modified the entities(matching:) method to support multi-field search with case-insensitive matching
  • Added entity ID matching to complement existing display name search
  • Added area name matching with nil-safe handling

Comment on lines +54 to +64
let matchDisplayString = entity.displayString.range(
of: string,
options: [.caseInsensitive, .diacriticInsensitive]
) != nil
let matchEntityId = entity.entityId.range(
of: string,
options: [.caseInsensitive, .diacriticInsensitive]
) != nil
let matchAreaName = {
if let area = entity.area {
return area.range(of: string, options: [.caseInsensitive, .diacriticInsensitive]) != nil
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The implementation uses range(of:options:) with case-insensitive options, but the codebase consistently uses the simpler .lowercased().contains() pattern for case-insensitive string matching in similar contexts. Consider using the established pattern for consistency:

let matchDisplayString = entity.displayString.lowercased().contains(string.lowercased())
let matchEntityId = entity.entityId.lowercased().contains(string.lowercased())

This pattern is used in other similar EntityQuery implementations like IntentCoverEntity, IntentLightEntity, IntentSwitchEntity, and ScriptAppIntent.

Suggested change
let matchDisplayString = entity.displayString.range(
of: string,
options: [.caseInsensitive, .diacriticInsensitive]
) != nil
let matchEntityId = entity.entityId.range(
of: string,
options: [.caseInsensitive, .diacriticInsensitive]
) != nil
let matchAreaName = {
if let area = entity.area {
return area.range(of: string, options: [.caseInsensitive, .diacriticInsensitive]) != nil
let matchDisplayString = entity.displayString.lowercased().contains(string.lowercased())
let matchEntityId = entity.entityId.lowercased().contains(string.lowercased())
let matchAreaName = {
if let area = entity.area {
return area.lowercased().contains(string.lowercased())

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +68
let matchAreaName = {
if let area = entity.area {
return area.range(of: string, options: [.caseInsensitive, .diacriticInsensitive]) != nil
} else {
return false
}
}()
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

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

The immediately-invoked closure pattern for matchAreaName adds unnecessary complexity. Consider simplifying using optional chaining for better readability:

let matchAreaName = entity.area?.lowercased().contains(string.lowercased()) ?? false

This is more concise and follows Swift idiomatic practices for handling optionals.

Suggested change
let matchAreaName = {
if let area = entity.area {
return area.range(of: string, options: [.caseInsensitive, .diacriticInsensitive]) != nil
} else {
return false
}
}()
let matchAreaName = entity.area?.range(of: string, options: [.caseInsensitive, .diacriticInsensitive]) != nil

Copilot uses AI. Check for mistakes.
@bgoncal bgoncal merged commit dad7295 into main Dec 10, 2025
16 checks passed
@bgoncal bgoncal deleted the copilot/add-search-matching-for-entities branch December 10, 2025 16:36
@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 10, 2025

Codecov Report

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

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4075   +/-   ##
=======================================
  Coverage        ?   45.78%           
=======================================
  Files           ?      242           
  Lines           ?    13621           
  Branches        ?        0           
=======================================
  Hits            ?     6236           
  Misses          ?     7385           
  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.

3 participants