Initial release v0.1.0
Home Assistant custom integration for NVIDIA Shield TV that composes the Android TV Remote, Jellyfin, smart plug, and receiver entities into a single unified media player with ADB-based now-playing from any app. Part of the Media Zone ecosystem. Entities: - media_player: power (with smart plug fallback), transport, input, volume routed to receiver, rich stream info overlay when Jellyfin is active - sensor: DAG attributes and stream info - button: Pair ADB Config: - Two-step flow: basic setup + optional ADB pairing on the Shield - Configurable ADB port (default 5555) - Pick an existing Jellyfin media_player entity — stream info is read from the HA Jellyfin integration's own DataUpdateCoordinator, so no server URL / API key / extra config needed here - Privacy mode (adb_store_app_info=False) suppresses non-Jellyfin media details, showing only the app name Ecosystem: - Exposes media_dag_* attributes for ha-media-zone orchestration - Exposes media_dag_running_apps and async_bring_to_foreground for the Media Zone card's app switcher Shared ADB code lives in ltomes/ha-adb-common and is vendored at custom_components/nvidia_shield/ha_adb_common/ for HACS installs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
0ad51879ae
24 files changed
+2538
No files matched your search
@@ -0,0 +1,48 @@
|
||||
"""Playback intent tracking for optimistic UI updates.
|
||||
|
||||
Bridges the gap between instant commands and slow state polling.
|
||||
"""
|
||||
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlaybackIntent:
|
||||
"""A pending user intent for playback state.
|
||||
|
||||
Attributes:
|
||||
target_state: The MediaPlayerState we expect after the command.
|
||||
command: The service/command name (for retries and logging).
|
||||
created_at: Monotonic timestamp when the intent was created.
|
||||
prior_state: The source state before the intent (for detecting external overrides).
|
||||
retry_count: Number of retries attempted so far.
|
||||
"""
|
||||
|
||||
target_state: str # MediaPlayerState value (e.g. "playing", "paused")
|
||||
command: str
|
||||
created_at: float
|
||||
prior_state: str | None = None
|
||||
retry_count: int = 0
|
||||
|
||||
@classmethod
|
||||
def create(cls, target_state: str, command: str, prior_state: str | None = None) -> "PlaybackIntent":
|
||||
return cls(
|
||||
target_state=target_state,
|
||||
command=command,
|
||||
created_at=time.monotonic(),
|
||||
prior_state=prior_state,
|
||||
)
|
||||
|
||||
@property
|
||||
def age_seconds(self) -> float:
|
||||
return round(time.monotonic() - self.created_at, 1)
|
||||
|
||||
def to_debug_dict(self) -> dict:
|
||||
"""Serialize for the _intent debug attribute."""
|
||||
return {
|
||||
"target": self.target_state,
|
||||
"command": self.command,
|
||||
"retries": self.retry_count,
|
||||
"age_s": self.age_seconds,
|
||||
}
|
||||
Reference in new issue
Block a user