HA integration: fix reload loop, parallel device fetch, WS guards, translations
- Fix indentation bug causing scenes device to not register - Use nonlocal tracking to prevent infinite reload loops on target/scene changes - Guard WS start/stop to avoid redundant connections - Parallel device brightness fetching via asyncio.gather - Route set_leds service to correct coordinator by source ID - Remove stale pattern cache, reuse single timeout object - Fix translations structure for light/select entities - Unregister service when last config entry unloaded Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -95,7 +95,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
model="Scene Presets",
|
||||
configuration_url=server_url,
|
||||
)
|
||||
current_identifiers.add(scenes_identifier)
|
||||
current_identifiers.add(scenes_identifier)
|
||||
|
||||
# Remove devices for targets that no longer exist
|
||||
for device_entry in dr.async_entries_for_config_entry(
|
||||
@@ -114,15 +114,17 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
}
|
||||
|
||||
# Track target and scene IDs to detect changes
|
||||
initial_target_ids = set(
|
||||
known_target_ids = set(
|
||||
coordinator.data.get("targets", {}).keys() if coordinator.data else []
|
||||
)
|
||||
initial_scene_ids = set(
|
||||
known_scene_ids = set(
|
||||
p["id"] for p in (coordinator.data.get("scene_presets", []) if coordinator.data else [])
|
||||
)
|
||||
|
||||
def _on_coordinator_update() -> None:
|
||||
"""Manage WS connections and detect target list changes."""
|
||||
nonlocal known_target_ids, known_scene_ids
|
||||
|
||||
if not coordinator.data:
|
||||
return
|
||||
|
||||
@@ -134,16 +136,20 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
state = target_data.get("state") or {}
|
||||
if info.get("target_type") == TARGET_TYPE_KEY_COLORS:
|
||||
if state.get("processing"):
|
||||
hass.async_create_task(ws_manager.start_listening(target_id))
|
||||
if target_id not in ws_manager._connections:
|
||||
hass.async_create_task(ws_manager.start_listening(target_id))
|
||||
else:
|
||||
hass.async_create_task(ws_manager.stop_listening(target_id))
|
||||
if target_id in ws_manager._connections:
|
||||
hass.async_create_task(ws_manager.stop_listening(target_id))
|
||||
|
||||
# Reload if target or scene list changed
|
||||
current_ids = set(targets.keys())
|
||||
current_scene_ids = set(
|
||||
p["id"] for p in coordinator.data.get("scene_presets", [])
|
||||
)
|
||||
if current_ids != initial_target_ids or current_scene_ids != initial_scene_ids:
|
||||
if current_ids != known_target_ids or current_scene_ids != known_scene_ids:
|
||||
known_target_ids = current_ids
|
||||
known_scene_ids = current_scene_ids
|
||||
_LOGGER.info("Target or scene list changed, reloading integration")
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_reload(entry.entry_id)
|
||||
@@ -156,11 +162,18 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Handle the set_leds service call."""
|
||||
source_id = call.data["source_id"]
|
||||
segments = call.data["segments"]
|
||||
# Route to the coordinator that owns this source
|
||||
for entry_data in hass.data[DOMAIN].values():
|
||||
coord = entry_data.get(DATA_COORDINATOR)
|
||||
if coord:
|
||||
if not coord or not coord.data:
|
||||
continue
|
||||
source_ids = {
|
||||
s["id"] for s in coord.data.get("css_sources", [])
|
||||
}
|
||||
if source_id in source_ids:
|
||||
await coord.push_segments(source_id, segments)
|
||||
break
|
||||
return
|
||||
_LOGGER.error("No server found with source_id %s", source_id)
|
||||
|
||||
if not hass.services.has_service(DOMAIN, "set_leds"):
|
||||
hass.services.async_register(
|
||||
@@ -188,5 +201,8 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
# Unregister service if no entries remain
|
||||
if not hass.data[DOMAIN]:
|
||||
hass.services.async_remove(DOMAIN, "set_leds")
|
||||
|
||||
return unload_ok
|
||||
|
||||
Reference in New Issue
Block a user