fix(ha): admit fan entities to the graph so fans are controllable#638
Open
minion1227 wants to merge 1 commit into
Open
fix(ha): admit fan entities to the graph so fans are controllable#638minion1227 wants to merge 1 commit into
minion1227 wants to merge 1 commit into
Conversation
`fan` is treated as a controllable domain throughout the stack — the quick router emits `home_control` for "turn on the ceiling fan" (shipped test), `infer_domain` and `domain_of_word` both resolve the `fan` domain, and `execute()` drives `fan.turn_on`/`turn_off`/`toggle` generically. But `is_voice_relevant_domain` — the gate `build_graph` uses to admit entities — omitted `fan`, so every `fan.*` entity was dropped from the graph before resolution. The result: "turn on the bedroom fan" failed with "no Home Assistant target matched", even though the fan existed and would actuate fine. Add `fan` as a first-class control domain, mirroring `switch`: - `is_voice_relevant_domain` admits `fan` (the actual fix) - `domain_synonyms`, `domain_label`, `domain_plural_label` give fans proper spoken/display strings instead of the generic "devices" - `capabilities_for` reports turn_on/turn_off for fans Regression test builds a graph from a `fan.*` entity and asserts it is admitted and resolves; it fails without the gate change.
matedev01
approved these changes
Jul 6, 2026
matedev01
left a comment
Contributor
There was a problem hiding this comment.
LGTM — admits fan entities to the HA graph. Clean HA fix.
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
Fans are silently uncontrollable:
fanis a first-class control domain everywhere in the stack except the one gate that admits entities into the resolution graph, so everyfan.*entity is dropped before resolution and any fan command fails.The bug
fanis treated as controllable throughout:home_control(shipped test,quick.rs), and listsfanas a known device (#523);infer_domainiterates["light","switch","fan","climate","cover","lock"]anddomain_of_wordmaps"fan"/"fans" → "fan";execute()drivesTurnOn/TurnOff/Togglegenerically viafan.turn_onetc.But
is_voice_relevant_domain— the filterbuild_graphuses to decide which entities enter the graph — omittedfan. So:This is an oversight, not a policy: fans aren't sensitive (not in the confirmation list), nothing marks
fanas excluded, and four other code paths already treat it as controllable.Changes
Add
fanas a first-class control domain inha/provider.rs, mirroringswitch:is_voice_relevant_domainadmitsfan— the actual fix that lets fan entities into the graph.domain_synonyms→["fan","fans"];domain_label/domain_plural_label→ fan singular/plural, so status summaries say "fan"/"fans" instead of the generic "devices".capabilities_forreportsturn_on/turn_offfor fans.Real Behavior Proof
Tested profile / hardware (check all that apply):
laptopNo Jetson-specific path; the resolution logic is deterministic and unit-testable against an in-memory graph, which is the equivalent verification.
What I ran
Linux laptop, x86-64, on this branch (based on current
main):What I observed
-D warnings; all 991 genie-core tests pass, 0 failures.build_graph_admits_fan_entities_and_resolves_them: builds a graph from onefan.bedroom_ceilingentity, asserts it is admitted tograph.entities, and thatresolve_target_in_graph("bedroom fan", TurnOn)resolves to it withdomain == "fan".is_voice_relevant_domainfan line reverted, the new test FAILS (panicked: fan entity should be admitted to the graph); restored, it passes. So the test genuinely captures the bug.Notes for reviewers
Scoped to
provider.rs, additive, and modeled exactly on the existingswitchdomain.execute()already handles the generic on/off/toggle service call, so no actuation changes are needed — the fix is purely admitting fans to the graph and giving them proper labels.