Skip to content

Support child devices - #5582

Draft
bgoncal wants to merge 12 commits into
mainfrom
bgoncal/child-devices
Draft

Support child devices#5582
bgoncal wants to merge 12 commits into
mainfrom
bgoncal/child-devices

Conversation

@bgoncal

@bgoncal bgoncal commented Aug 31, 2026

Copy link
Copy Markdown
Member

AI Policy

Select exactly one option that describes AI usage in this contribution:

  • I have not used AI for this contribution.
  • AI assistance was used for this contribution.
  • AI fully generated the code for this contribution, but I've reviewed and understood it before submitting and will respond without AI during review.

Summary

Adds support for child devices (core PR home-assistant/core#178666, frontend PRs home-assistant/frontend#53617 and home-assistant/frontend#53619), where a device can be a logical part of another one, e.g. one outlet of a power strip.

Children arrive on config/device_registry/list stripped of everything they inherit from their parent, so, like the frontend does, they are resolved into complete devices at ingestion: hardware and display fields come from the parent, the config entry from the child's own config_entry_id, and identity fields are never inherited. A child without an area of its own now inherits its parent's, so its entities keep showing up in areas (watch areas, CarPlay areas, area actions, entity picker).

On the watch, a child device's section sorts under its parent and shows what it is part of, and a parent's device screen also lists its children's entities. Searching the parent's name finds a child's entities, both in the entity picker and in Spotlight.

Also adds a "Group by Device" option to the entity picker, with child devices listed under their parent.

Screenshots

To be added.

Link to pull request in Documentation repository

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

Any other notes

Servers without child devices are unaffected: the new fields are simply absent and every device behaves as before.

Copilot AI lite review requested due to automatic review settings August 31, 2026 11:03

@home-assistant home-assistant Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hello @bgoncal,

When attempting to inspect the commits of your pull request for CLA signature status among all authors we encountered commit(s) which were not linked to a GitHub account, thus not allowing us to determine their status(es).

The commits that are missing a linked GitHub account are the following:

Unfortunately, we are unable to accept this pull request until this situation is corrected.

Here are your options:

  1. If you had an email address set for the commit that simply wasn't linked to your GitHub account you can link that email now and it will retroactively apply to your commits. The simplest way to do this is to click the link to one of the above commits and look for a blue question mark in a blue circle in the top left. Hovering over that bubble will show you what email address you used. Clicking on that button will take you to your email address settings on GitHub. Just add the email address on that page and you're all set. GitHub has more information about this option in their help center.

  2. If you didn't use an email address at all, it was an invalid email, or it's one you can't link to your GitHub, you will need to change the authorship information of the commit and your global Git settings so this doesn't happen again going forward. GitHub provides some great instructions on how to change your authorship information in their help center.

    • If you only made a single commit you should be able to run
      git commit --amend --author="Author Name <[email protected]>"
      
      (substituting "Author Name" and "[email protected]" for your actual information) to set the authorship information.
    • If you made more than one commit and the commit with the missing authorship information is not the most recent one you have two options:
      1. You can re-create all commits missing authorship information. This is going to be the easiest solution for developers that aren't extremely confident in their Git and command line skills.
      2. You can use this script that GitHub provides to rewrite history. Please note: this should be used only if you are very confident in your abilities and understand its impacts.
    • Whichever method you choose, I will come by to re-check the pull request once you push the fixes to this branch.

We apologize for this inconvenience, especially since it usually bites new contributors to Home Assistant. We hope you understand the need for us to protect ourselves and the great community we all have built legally. The best thing to come out of this is that you only need to fix this once and it benefits the entire Home Assistant and GitHub community.

Thanks, I look forward to checking this PR again soon! ❤️

@home-assistant
home-assistant Bot marked this pull request as draft August 31, 2026 11:03
@home-assistant

Copy link
Copy Markdown

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

home-assistant[bot]

This comment was marked as outdated.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds end-to-end support for Home Assistant “child devices” (devices that are logical parts of a parent device) across ingestion, persistence, watch UI, Spotlight search, area resolution, and the entity picker UI.

Changes:

  • Resolve stripped child-device registry entries at ingestion time by inheriting hardware/display fields from the parent while keeping identity/config-entry fields on the child.
  • Make child devices inherit their parent’s area when the child has no area, so area-based features continue to surface child entities correctly.
  • Improve presentation and search: watch device/area screens sort child device sections under the parent and show “Part of …”; Spotlight and entity search incorporate parent naming; entity picker gains “Group by Device”.

Reviewed changes

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

Show a summary per file
File Description
Tests/Shared/Watch/WatchGroupedEntities.test.swift Adds watch grouping tests for child sorting and per-device flattening.
Tests/Shared/Models/DeviceRegistry.test.swift Adds decoding + child-resolution + effective-area unit tests.
Tests/App/EntityPicker/EntityPickerViewModel.test.swift Adds test coverage for “Group by Device” behavior including child placement.
Tests/App/Area/AreasService.test.swift Adds test ensuring child entities land in the parent’s area when child has none.
Sources/WatchApp/Home/Devices/WatchDeviceEntitiesViewModel.swift Includes child-device entities when viewing a parent device; flattens parent grouping.
Sources/WatchApp/Home/Devices/WatchDeviceEntitiesView.swift Keeps child-device sections on device screen while unwrapping the viewed device’s own section.
Sources/WatchApp/Home/Areas/WatchAreaDeviceSectionHeader.swift Shows “Part of …” subtitle for child device section headers (configurable).
Sources/Shared/Watch/WatchGroupedEntities.swift Adds parent name to device groups, sorts child groups under parent, and adds flattening helper.
Sources/Shared/Watch/WatchEntitySections.swift Enriches watch entity entries with parent device naming for child devices.
Sources/Shared/Watch/WatchEntityEntry.swift Extends watch entry device metadata with optional parent name.
Sources/Shared/Resources/Swiftgen/Strings.swift Updates SwiftGen accessors for new Localizable keys.
Sources/Shared/Environment/EntityFuzzySearch/EntityFuzzySearchIndex.swift Improves fuzzy search by combining child + parent device names.
Sources/Shared/Environment/DeviceRegistryEntry.swift Decodes child-specific fields and resolves child devices during registry ingestion.
Sources/Shared/Environment/AppDatabaseUpdater.swift Uses child-device resolution when persisting device registry updates.
Sources/Shared/Database/AppDeviceRegistryTable.swift Adds parentDeviceId column (indexed) to the GRDB device registry table.
Sources/Shared/AreasService.swift Uses effective-area logic so child devices inherit parent area when appropriate.
Sources/HAModels/Sources/DatabaseTables.swift Adds parentDeviceId to device-registry column definitions.
Sources/HAModels/Sources/AppDeviceRegistry.swift Persists parentDeviceId and adds effectiveAreaId(in:) helper.
Sources/Extensions/Widgets/HAAppEntityAppIntentEntity.swift Adds parentDeviceName field to support Spotlight keywording.
Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift Indexes parent-device name for child devices to improve Spotlight search matches.
Sources/App/Utilities/Spotlight/HAAppEntityAppIntentEntity+IndexedEntity.swift Includes parent-device name in Spotlight keywords/contextual names.
Sources/App/Settings/EntityPicker/EntityPickerViewModel.swift Adds device grouping mode and caches for device-based grouping/sorting.
Sources/App/Settings/EntityPicker/EntityPickerGroup.swift Makes group identity stable via explicit id (not derived from title).
Sources/App/Settings/EntityPicker/EntityPicker.swift Updates grouping UI visibility logic to account for device grouping.
Sources/App/Resources/en.lproj/Localizable.strings Adds English strings for “Group by Device”, “No device”, and “Part of %@”.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Sources/Shared/Watch/WatchEntitySections.swift
Comment thread Sources/App/Utilities/Spotlight/SpotlightEntityIndexer.swift
Comment thread Sources/WatchApp/Home/Devices/WatchDeviceEntitiesView.swift Outdated
@bgoncal
bgoncal marked this pull request as ready for review August 31, 2026 12:42
@home-assistant
home-assistant Bot dismissed stale reviews from themself August 31, 2026 12:42

Stale

@bgoncal
bgoncal requested a balanced review from Copilot August 31, 2026 12:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 30 out of 30 changed files in this pull request and generated 3 comments.

Suppressed comments (1)

Sources/App/Settings/EntityPicker/EntityPickerViewModel.swift:185

  • These detached rebuilds are not ordered. The initial Published emission can start a rebuild with an empty entity cache, then fetchEntities() starts a populated rebuild for the same server; because the guard checks only serverId, the older empty result can finish last and erase all subtitles/icons. Retain and cancel a row-content task or use a dedicated generation token, and clear the published maps when starting a server change.
        Task.detached(priority: .userInitiated) { [weak self] in
            let subtitles = serverEntities.contextualSubtitles(for: serverId)
            let icons = serverEntities.reduce(into: [String: MaterialDesignIcons]()) { icons, entity in
                icons[entity.entityId] = entity.materialDesignIcon
            }
            await MainActor.run { [weak self] in
                guard let self, selectedServerId == serverId else { return }

Comment thread Sources/App/Settings/EntityPicker/EntityPickerViewModel.swift Outdated
Comment thread Sources/Shared/Watch/WatchGroupedEntities.swift
Comment thread Sources/Shared/AreasService.swift
@bgoncal
bgoncal marked this pull request as draft August 31, 2026 15:18
@bgoncal

bgoncal commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

On hold until further definition in frontend

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

⚠️ Unused L10n strings detected

Found 1 unused localization strings in the codebase.

Click to see details
Parsing Strings.swift...
Found 2633 L10n strings

Reading all Swift source code...
Read 10615371 characters of Swift code

Checking for unused strings...
Checked 100/2633 strings...
Checked 200/2633 strings...
Checked 300/2633 strings...
Checked 400/2633 strings...
Checked 500/2633 strings...
Checked 600/2633 strings...
Checked 700/2633 strings...
Checked 800/2633 strings...
Checked 900/2633 strings...
Checked 1000/2633 strings...
Checked 1100/2633 strings...
Checked 1200/2633 strings...
Checked 1300/2633 strings...
Checked 1400/2633 strings...
Checked 1500/2633 strings...
Checked 1600/2633 strings...
Checked 1700/2633 strings...
Checked 1800/2633 strings...
Checked 1900/2633 strings...
Checked 2000/2633 strings...
Checked 2100/2633 strings...
Checked 2200/2633 strings...
Checked 2300/2633 strings...
Checked 2400/2633 strings...
Checked 2500/2633 strings...
Checked 2600/2633 strings...

================================================================================
UNUSED STRINGS REPORT
================================================================================

Found 1 unused strings:


WIDGETS:
  - L10n.Widgets.Energy.electricityTotal
    Key: widgets.energy.electricity_total
    Line: 9011

================================================================================
Total unused: 1
================================================================================

================================================================================
Copy-paste these keys into the "Lokalise: Delete Keys" workflow (keys input):
================================================================================
widgets.energy.electricity_total

To remove them, run the
Lokalise: Delete Keys
workflow — it deletes the keys from Lokalise and opens a PR removing them from
Localizable.strings and regenerating Strings.swift. Copy-paste these keys into the keys input:

widgets.energy.electricity_total

@codecov

codecov Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.54839% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.93%. Comparing base (c3d1737) to head (bc67c9b).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...urces/App/Settings/EntityPicker/EntityPicker.swift 0.00% 5 Missing ⚠️
...p/Utilities/Spotlight/SpotlightEntityIndexer.swift 0.00% 4 Missing ⚠️
.../Settings/EntityPicker/EntityPickerViewModel.swift 96.10% 3 Missing ⚠️
Sources/Shared/Watch/WatchGroupedEntities.swift 93.10% 2 Missing ⚠️
Sources/Extensions/EntityProvider+Details.swift 95.83% 1 Missing ⚠️
...ources/Shared/Environment/AppDatabaseUpdater.swift 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5582      +/-   ##
==========================================
+ Coverage   35.29%   35.93%   +0.63%     
==========================================
  Files        1013     1032      +19     
  Lines       73124    74255    +1131     
==========================================
+ Hits        25812    26681     +869     
- Misses      47312    47574     +262     
Files with missing lines Coverage Δ
.../App/Settings/EntityPicker/EntityPickerGroup.swift 100.00% <100.00%> (+100.00%) ⬆️
...rces/App/Settings/EntityPicker/EntityRowView.swift 95.08% <100.00%> (+95.08%) ⬆️
...ght/HAAppEntityAppIntentEntity+IndexedEntity.swift 100.00% <100.00%> (+100.00%) ⬆️
...xtensions/Widgets/HAAppEntityAppIntentEntity.swift 24.39% <100.00%> (+24.39%) ⬆️
Sources/Shared/AreasService.swift 38.67% <100.00%> (+3.03%) ⬆️
...urces/Shared/Database/AppDeviceRegistryTable.swift 97.87% <100.00%> (+0.04%) ⬆️
...urces/Shared/Environment/DeviceRegistryEntry.swift 100.00% <100.00%> (ø)
...ent/EntityFuzzySearch/EntityFuzzySearchIndex.swift 92.45% <100.00%> (+2.86%) ⬆️
Sources/Shared/Watch/WatchEntityEntry.swift 90.00% <100.00%> (+2.50%) ⬆️
Sources/Shared/Watch/WatchEntitySections.swift 97.91% <100.00%> (+97.91%) ⬆️
... and 6 more

... and 46 files with indirect coverage changes

☔ View full report in Codecov by Harness.
📢 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.

2 participants