8.1 KiB
NVIDIA Shield
Home Assistant integration for the NVIDIA Shield TV — ADB media session tracking for now-playing state from any app, plus Google remote-protocol commands, Jellyfin rich metadata, and power monitoring.
This is a Shield-only fork of ltomes/ha-nvidia-shield
(early 0.1.x), rebuilt around a different architecture: one integration, one device,
ADB as the state source, and no dependency on separate androidtv / androidtv_remote
integrations.
Status: early fork, actively rebuilt. Releases are date-based (
v2026.10.08). Expect rough edges until the MVP phases land. The build-out plan is indocs/MVP_PLAN.md; device research is indocs/RESEARCH_SHIELD.md.
What we're building (the fork's goals)
The fork exists to make a single integration own the Shield end-to-end:
- Event-driven ADB media session tracking as the primary playback state source —
dumpsys media_sessionover a persistent connection, not screen capture, not 10-second polling. - Fallback state for apps without media sessions — e.g. TiviMate publishes
none at all; foreground-app detection (
mResumedActivity) + last-known-state- the "audio playback" hint from the same session dump close that gap.
- All-in-one device — absorb the Google remote protocol (
androidtvremote2): aremoteentity alongside the media player,play_mediawithmedia_content_type: channelfor TiviMate channel-by-number, absolute volume, focused-app push events. ADB stays the playback-state source; ADB pairing stays intact. - Retire the surrounding glue — the
mediasession2mqttbridge, universal media player templates, and external remote entity reading all become native integration behavior.
Phases 0–4 with files, risks, and definitions of done live in
docs/MVP_PLAN.md.
Current features (inherited from upstream 0.1.x)
- ADB Media Session — now-playing from any app that publishes a session (Spotify, Netflix, Plex, Wholphin, …)
- Jellyfin rich metadata — title, series/episode, position, stream details (resolution, codec, HDR, audio format) via the HA Jellyfin integration's cache
- Power monitoring — smart plug for reliable on/off with auto-discovered sibling sensors (watts, voltage, current)
- Intent tracking — commands reflect in HA state immediately, self-heal against actual device state
- Privacy mode — show only app name without media details for non-Jellyfin apps
- Media DAG attributes —
media_dag_*attributes for media-zone style orchestration
Changes inherited from upstream still apply in 0.1.x code: polling is timer-based, the ADB connection lives inside the media player entity, and fallback app state arrives in Phase 3.
State ladder and fallback semantics (Phase 3)
The media player state is decided top-down; each tier serves only when the
ones above it are silent. Both transports live in the entry's
ShieldConnectionManager (connection.py) — ADB is the state source, the
remote protocol is the fast push/command path:
- Plug off — the power switch says
off→off. - Protocol power push (
is_on) —False→off;Nonefalls through. - ADB wake (exact
mWakefulnessparse) — asleep →idle(standby). - Intent — a just-sent command's target state, self-healing against reality within 30 s (retry goes over the transport that served it).
- Jellyfin —
playing/pausedwhile a Jellyfin session is active. - ADB media session —
playing/pausedfor apps that publish a session (foreground app preferred). - Foreground fallback — an app is open (
current_appprotocol push, then the ADBmResumedActivityparse) but publishes no media session →on. Its identity comes from the TTL-capped last-known-state cache, the last channel entered, or the zero-cost "audio playback" hint (media recently active) — never resurrectingplayingpast the 60 s state TTL. - On — powered, awake, nothing more specific.
TiviMate (ar.tvplayer.tv) is the documented no-session case: it publishes
no MediaSession on Shield Android 11 (RESEARCH_SHIELD R2), so tiers 6–7 plus
the audio hint are what keep it visible.
Standalone setup accepts any one of the three state sources — the Android
TV Remote entity, the Nvidia Remote Protocol (PIN pairing), or ADB
media-session mode (ADB enabled + host). The no_state_source form error
fires only when none of the three is present; ADB-only setups are valid.
Migration from mediasession2mqtt + universal-player glue
The mediasession2mqtt bridge sensors and the universal media player YAML
templates the fork replaces are retired by the ladder above: the media player
entity already carries the DAG attributes (media_dag_running_apps with
foreground/last-known enrichment, media_dag_now_playing with its source
tag) that media-zone orchestration consumed from those sensors. See the
appendix in docs/RESEARCH_SHIELD.md for the
retirement mapping and the universal-player glue it replaces.
Releases
- Date-based versioning:
vYYYY.MM.DD(e.g.v2026.10.08). - Pushes to
masteron Gitea run the release workflow (.github/workflows/release.yml):- A plain push publishes the current day's release (same-day pushes are deduped).
- Bumping
versionincustom_components/nvidia_shield/manifest.jsonforces that specific version's release before the date fallback kicks in.
- Releases land on Gitea with the tag and a
nvidia_shield.zipasset for manual installs. (No automatic mirroring — see the HACS note below.)
Installation
HACS
HACS only works with public GitHub repositories, so the Gitea repo cannot be added to HACS directly. If you set up a public GitHub mirror of the releases, add it as a custom repository:
- In HACS, open the overflow menu (⋮) → Custom repositories.
- Paste
https://github.com/notexpectedyet/ha-nvidia-shield, pick type Integration, click Add. - Find NVIDIA Shield in the HACS list and click Download.
- Restart Home Assistant.
Manual
Copy custom_components/nvidia_shield to your HA config/custom_components/
directory, restart, then add the integration from Settings → Devices & Services.
Configuration
- Settings > Devices & Services > Add Integration > "NVIDIA Shield"
- Select the Android TV Remote entity for your Shield
- Enable ADB if you want now-playing from all apps
- If ADB is enabled, the next step will pair — approve the prompt on the Shield
- Optionally configure Jellyfin, receiver, power switch
ADB Pairing
ADB is paired during setup via a dedicated config flow step. If you need to re-pair later (e.g. after factory reset), use the "Pair ADB" button on the device page in HA.
Requirements: Settings > Developer options > Network debugging enabled on the Shield.
Options
- Jellyfin Media Player — auto-detected or manually selected
- Receiver + Input — for media-zone coordination
- Power Switch — smart plug entity
- ADB Host/Port — override auto-detection if needed
Entities
| Entity | Type | Description |
|---|---|---|
| Media Player | media_player |
Main entity with playback controls and metadata |
| Current App | sensor |
Currently running app |
| Now Playing | sensor |
Formatted now-playing string |
| Pair ADB | button |
Initiate or re-pair ADB connection |
Development
- Repository: Gitea — git.notexpectedyet.com/notexpectedyet/ha-nvidia-shield, branch
master - CI/CD: Gitea Actions; every push to
masterreleases (see.gitea/workflows/release.yml). Auth uses the job-providedGITEA_TOKEN— no extra secrets required. - Shared ADB helpers are vendored at
custom_components/nvidia_shield/ha_adb_common/(trimmed in this fork); dev extras inpyproject.toml(uv sync --extra dev).
License
MIT