diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c4354d..90d2122 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- A media player renamed in Home Assistant (new entity id) no longer disappears + from the sidebar until the page is reloaded. + ### Changed - Now in the HACS default store: install by searching for Sidebar Mini Player in HACS, no custom repository needed. README badge and install steps updated. diff --git a/ha-sidebar-mini-player.js b/ha-sidebar-mini-player.js index 792c30f..07d0af2 100644 --- a/ha-sidebar-mini-player.js +++ b/ha-sidebar-mini-player.js @@ -309,15 +309,16 @@ /** * Cached list of candidate media_player ids. A large install has thousands * of entities; we only re-list hass.states' keys when the states object - * changed AND its key count changed (entity added/removed), or the config - * changed. Otherwise each tick only looks at the cached media players. + * changed AND its key count changed (entity added/removed) or a cached + * player is gone (entity renamed: one id out, one in, same count), or the + * config changed. Otherwise each tick only looks at the cached media players. */ const cache = { states: null, count: -1, ids: [] }; function mediaPlayerIds(states) { if (states !== cache.states) { cache.states = states; const keys = Object.keys(states); - if (keys.length !== cache.count) { + if (keys.length !== cache.count || cache.ids.some((id) => !(id in states))) { cache.count = keys.length; cache.ids = keys.filter((id) => id.startsWith("media_player.") && allowed(id)); } diff --git a/test/test.js b/test/test.js index 6890a91..df8439f 100644 --- a/test/test.js +++ b/test/test.js @@ -308,6 +308,13 @@ function setup(layoutHtml, statesFile = FIXTURE, prep = null, opts = {}) { // New Speaker is now the most recent playing -> auto focus (no click choice made in this run). check("V3 newly added entity discovered + auto-focused (5 active)", q3(".spk").textContent === "New Speaker" && R3.querySelectorAll(".mini").length === 4, `${q3(".spk").textContent}, minis=${R3.querySelectorAll(".mini").length}`); + // Entity renamed (one id out, one in, so the key count stays the same) -> still shown. + const stR = { ...t3.ha.hass.states }; + delete stR["media_player.new_speaker"]; + stR["media_player.renamed_speaker"] = { entity_id: "media_player.renamed_speaker", state: "playing", last_changed: new Date().toISOString(), attributes: { friendly_name: "Renamed Speaker", media_title: "Hello" } }; + t3.ha.hass = { ...t3.hass, states: stR }; await sleep(1200); + check("V3 renamed entity (same entity count) picked up", q3(".spk").textContent === "Renamed Speaker" && R3.querySelectorAll(".mini").length === 4, + `${q3(".spk").textContent}, minis=${R3.querySelectorAll(".mini").length}`); // Cap: add 3 more -> 8 active, 7 others -> 4 cards + "+3 more" at the top. const st4 = { ...t3.ha.hass.states }; for (const k of ["a", "b", "c"]) st4["media_player.extra_" + k] = { entity_id: "media_player.extra_" + k, state: "paused", last_changed: new Date(Date.now() - 4 * 60000).toISOString() /* < 5 min */, attributes: { friendly_name: "Extra " + k.toUpperCase(), media_title: "T" + k } };