feat(button,media_player): Pair ADB carries entity_category CONFIG (t30 G11) + BrowseMediaSource domain parameter at root and children (t30 G18, 2026-05-20 blog contract); stubs/tests pin both

This commit is contained in:
James Mackay committed 2026-10-09 07:17:14 +01:00
1 parent 7c12d96070
commit 194a97ce34
4 files changed
+15 -1

No files matched your search

+2 -1
View File
@@ -5,7 +5,7 @@ import logging
from homeassistant.components.button import ButtonEntity from homeassistant.components.button import ButtonEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo, EntityCategory
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .adb_session import AdbMediaSessionPoller, ensure_adb_key from .adb_session import AdbMediaSessionPoller, ensure_adb_key
@@ -36,6 +36,7 @@ class NvidiaShieldPairAdbButton(ButtonEntity):
_attr_has_entity_name = True _attr_has_entity_name = True
_attr_name = "Pair ADB" _attr_name = "Pair ADB"
_attr_entity_category = EntityCategory.CONFIG
_attr_icon = "mdi:link-variant" _attr_icon = "mdi:link-variant"
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None: def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
@@ -941,6 +941,8 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
) )
app_map = self._entry.options.get(CONF_APP_NAME_MAP) or DEFAULT_APP_DIRECTORY app_map = self._entry.options.get(CONF_APP_NAME_MAP) or DEFAULT_APP_DIRECTORY
# G18 (2026-05-20 blog): BrowseMediaSource must carry the domain
# parameter so the frontend can attribute the media tree.
children = [ children = [
BrowseMediaSource( BrowseMediaSource(
title=name, title=name,
@@ -949,6 +951,7 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
media_content_id=pkg, media_content_id=pkg,
can_play=True, can_play=True,
can_expand=False, can_expand=False,
domain=DOMAIN,
) )
for pkg, name in app_map.items() for pkg, name in app_map.items()
] ]
@@ -960,6 +963,7 @@ class NvidiaShieldMediaPlayer(MediaPlayerEntity):
can_play=False, can_play=False,
can_expand=True, can_expand=True,
children=children, children=children,
domain=DOMAIN,
) )
# ── play_media (§7): channel digits, app/url launch ── # ── play_media (§7): channel digits, app/url launch ──
+5
View File
@@ -78,6 +78,7 @@ class BrowseMediaSource:
media_content_id, media_content_id,
can_play, can_play,
can_expand, can_expand,
domain=None, # t30 G18 (2026-05-20 blog contract)
children=None, children=None,
thumbnail=None, thumbnail=None,
): ):
@@ -87,6 +88,7 @@ class BrowseMediaSource:
self.media_content_id = media_content_id self.media_content_id = media_content_id
self.can_play = can_play self.can_play = can_play
self.can_expand = can_expand self.can_expand = can_expand
self.domain = domain
self.children = children or [] self.children = children or []
self.thumbnail = thumbnail self.thumbnail = thumbnail
@@ -287,6 +289,9 @@ def install() -> None:
) )
entity = types.ModuleType("homeassistant.helpers.entity") entity = types.ModuleType("homeassistant.helpers.entity")
entity.DeviceInfo = dict entity.DeviceInfo = dict
entity.EntityCategory = types.SimpleNamespace(
CONFIG="config", DIAGNOSTIC="diagnostic"
)
helpers.entity = entity helpers.entity = entity
entity_platform = types.ModuleType("homeassistant.helpers.entity_platform") entity_platform = types.ModuleType("homeassistant.helpers.entity_platform")
entity_platform.AddEntitiesCallback = object entity_platform.AddEntitiesCallback = object
+4
View File
@@ -971,6 +971,10 @@ class TestBrowseMediaDirectory:
("com.netflix.ninja", "Netflix"), ("com.netflix.ninja", "Netflix"),
] ]
assert all(c.media_content_type == "app" for c in root.children) assert all(c.media_content_type == "app" for c in root.children)
# t30 G18 (2026-05-20 blog): the domain parameter is present at
# every level of the tree
assert root.domain == "nvidia_shield"
assert all(c.domain == "nvidia_shield" for c in root.children)
async def test_root_falls_back_to_the_curated_default(self, modules): async def test_root_falls_back_to_the_curated_default(self, modules):
player, _s, _i = make_player(modules) # no apps map configured player, _s, _i = make_player(modules) # no apps map configured