Climate, weather and media_player icons never reflected their state - #221
Conversation
entityIsActive only ever recognised the literal state "on" (or a small per-domain set for lock/vacuum/camera) as active. A climate entity's state *is* its HVAC mode — "cool", "heat", "dry" — never "on", so a running unit always read as off: no active highlight, and a configured iconAnimation never played however it was actually running. A media player reporting "paused"/"idle"/"buffering" instead of "playing" had the same problem — still switched on, read as off. climate and media_player each get their own active-state set now, mirroring lock/vacuum/camera: every HVAC mode but "off", and every media_player state but "off". Separately, climate and weather had no state-aware icon at all — DOMAIN_STATE_ICONS only ever expressed a two-way on/off choice, and neither domain's meaning is binary. A climate item always drew the bare thermostat glyph regardless of mode, and a weather item — with no device class and no domain entry — drew entityDefaultIcon's plain fallback circle whatever the sky was doing. Adds CLIMATE_MODE_ICONS (one icon per HVAC mode, HA's own climate.HVACMode enum) and WEATHER_CONDITION_ICONS (one per condition, HA's own ATTR_CONDITION_* set), and threads the entity's raw state into entityDefaultIcon so it can pick from them. A climate entity in fan_only always spins regardless of iconAnimation — its own fan is what's running, the same physical fact that makes a `fan` domain entity spin by default, just decided from this entity's state rather than its domain; `none` still wins over it.
There was a problem hiding this comment.
🟡 Changes recommended
The media_player “active” state logic contradicts the PR description by excluding the standby state, so behavior and tests should be aligned with the stated requirement.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes state handling for Home Assistant climate, weather, and media_player entities so the floorplan card can correctly determine “active” state (for highlight + icon animation) and choose a state-appropriate default icon for non-binary domains.
Changes:
- Add HVAC-mode → icon mapping for
climateand condition → icon mapping forweather, and pass raw entitystateintoentityDefaultIcon. - Expand
entityIsActivedomain-specific active-state handling forclimateandmedia_player. - Add/adjust unit tests covering the new icon selection and active-state behavior.
File summaries
| File | Description |
|---|---|
| src/render.ts | Adds climate/weather state→icon mappings, updates active-state handling, and threads state into default icon selection. |
| src/render.test.ts | Adds test coverage for climate/weather icon selection and new active-state expectations. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
nicosandller
left a comment
There was a problem hiding this comment.
Approve — clean, well-scoped fix.
Behaviour is unchanged for every domain and state outside the three this touches: each new branch in entityDefaultIcon returns early only for climate / weather, the ACTIVE_STATES additions sit beside the existing lock/vacuum/camera sets, and the resolveIconAnimation line is gated below the none and fail-closed guards. The icon and active-state maps track HA's own HVACMode and ATTR_CONDITION_* enums; unrecognised values fall back to the previous glyph rather than to nothing; card and editor stay in sync because both resolve through resolveItemIcon, which now threads st.state. Every branch has a test, tsc is clean, and the full suite is green (1202).
Rendered every state against the main and PR bundles — before/after for climate, weather and media_player here: https://claude.ai/code/artifact/d910c002-55bc-4d6f-a51e-ffe1cc5da870
Two small notes, neither blocking:
entityDefaultIconformedia_playerstill keys only on/off, sopaused/idlenow drawmdi:television-play. "It's on" is the right semantic and it matches the amber highlight, but a distinct pause glyph would be a nice follow-up.climatecountsheat/cool/ … as active regardless ofhvac_action, so a thermostat inheatmode but currently idle (setpoint satisfied) reads as active. That matches HA's own Tile card and is overridable with a state rule onhvac_action, so it's fine — just flagging the choice.
One request before merge
The demo plan (docker/config/floorplan-demo.yaml) has no climate.*, weather.* or media_player.* device on either floor, so none of this is visible in the dev container — only in the unit tests. The demo integration already ships climate.heatpump / climate.hvac / climate.ecobee, a weather.* entity and several media_player.*.
Could we add a few of these to the default plan — and ideally have the sample-data automation walk a climate entity through its HVAC modes the way the covers already cycle position — so the feature has a visible home, the same way the per-leaf sensors and multi-reading badges do?
|
@diegocjorge I approved but could you add these new feature examples on the dev container so we can keep an aye on them in the future? |
nicosandller asked for these on PR nicosandller#221's review: the plan had nothing that reflected any of the three domains this PR touches, so a future change here has nothing to visibly break. - climate.hvac (issue nicosandller#206's own reproduction: boots into "cool", not "on", and is the one demo climate entity whose hvac_modes include fan_only) with iconAnimation: spin, matching the original report. - weather.demo_weather_south and weather.demo_weather_north side by side, the same pairing glow_warm/glow_cool already use above -- a demo weather entity's condition never changes, so two fixed ones is the only way to see more than one WEATHER_CONDITION_ICONS entry on the plan at once. - media_player.walkman, which boots "playing"; media_player.media_pause from Developer Tools > Actions flips it to "paused" without turning the badge off. All four come from the existing demo: integration already enabled in configuration.yaml, so no other config file changes.
nicosandller flagged this on PR nicosandller#221's review: paused/idle correctly read as active now, but both drew the same television-play glyph as "playing" -- right about being on, but silent about not being mid-playback. Adds one override ahead of the generic on/off table: media_player in "paused" draws mdi:television-pause. Every other active state (on, idle, playing, buffering) keeps the plain play glyph, since none of them needed their own icon before this -- only paused visibly differs from "is something happening" now that it counts as on. The other note on that same review -- a climate entity reading active in heat/cool regardless of hvac_action -- is left as is per the reviewer's own comment: it matches HA's Tile card and is already overridable with a state rule on hvac_action.
Following up on the pause-icon fix: idle is on with nothing loaded at all, and was still drawing the plain television-play glyph -- same problem as paused had, one commit ago. Folded both into one small MEDIA_PLAYER_STATE_ICONS table now that there are two exceptions instead of a single override. idle -> mdi:television (plain), chosen over mdi:television-stop since nothing was actually stopped -- there may never have been anything playing at all.
|
Added the pause icon ( On the |
entityIsActive only ever recognised the literal state "on" (or a small per-domain set for lock/vacuum/camera) as active. A climate entity's state is its HVAC mode — "cool", "heat", "dry" — never "on", so a running unit always read as off: no active highlight, and a configured iconAnimation never played however it was actually running. A media player reporting "paused"/"idle"/"buffering" instead of "playing" had the same problem — still switched on, read as off.
climate and media_player each get their own active-state set now, mirroring lock/vacuum/camera: every HVAC mode but "off", and every media_player state but "off".
Separately, climate and weather had no state-aware icon at all — DOMAIN_STATE_ICONS only ever expressed a two-way on/off choice, and neither domain's meaning is binary. A climate item always drew the bare thermostat glyph regardless of mode, and a weather item — with no device class and no domain entry — drew entityDefaultIcon's plain fallback circle whatever the sky was doing.
Adds CLIMATE_MODE_ICONS (one icon per HVAC mode, HA's own climate.HVACMode enum) and WEATHER_CONDITION_ICONS (one per condition, HA's own ATTR_CONDITION_* set), and threads the entity's raw state into entityDefaultIcon so it can pick from them. A climate entity in fan_only always spins regardless of iconAnimation — its own fan is what's running, the same physical fact that makes a
fandomain entity spin by default, just decided from this entity's state rather than its domain;nonestill wins over it.