"""Shared base entity for scene-playlist platforms. The playlist switch and the playlist stats sensors live on the same device and share the same lookup, availability, and running-state logic. Keeping that in one place means the snapshot key names (``scene_playlists`` / ``playlist_state``) and the "is this the active playlist?" match only ever live once, so the switch and sensors can't silently drift apart. """ from __future__ import annotations from typing import Any from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN from .coordinator import LedGrabCoordinator class LedGrabPlaylistEntity(CoordinatorEntity): """Common plumbing for entities attached to a scene-playlist device.""" _attr_has_entity_name = True def __init__( self, coordinator: LedGrabCoordinator, playlist_id: str, entry_id: str, ) -> None: super().__init__(coordinator) self._playlist_id = playlist_id self._entry_id = entry_id @property def device_info(self) -> dict[str, Any]: return {"identifiers": {(DOMAIN, self._playlist_id)}} @property def available(self) -> bool: return self._get_playlist() is not None def _get_playlist(self) -> dict[str, Any] | None: if not self.coordinator.data: return None for playlist in self.coordinator.data.get("scene_playlists", []): if playlist.get("id") == self._playlist_id: return playlist return None def _running_state(self) -> dict[str, Any] | None: """Return the global cycling state if this playlist is the active one.""" if not self.coordinator.data: return None state = self.coordinator.data.get("playlist_state") or {} if state.get("is_running") and state.get("playlist_id") == self._playlist_id: return state return None