docs(readme): the app list as sources, the remote command script, current versioning (t47 D)

t46 F2: the status line still cited `v2026.10.08`. It now describes the scheme
(`vYYYY.MM.DD`, plus `vYYYY.MM.DD.N` for a second release in the same day) and links
to the Releases section, so it cannot go stale again. The other dated reference stays:
"v2026.10.09 shipped that way" is the historical example that motivated the write-back,
and it is accurate.

New "Sources (the app list in a dropdown)" section: source_list from the Apps map
(with the built-in fallback named, so a card is never empty), `source` resolved exactly
like the Current App sensor, and `media_player.select_source` by name — accepting a raw
package id and any case, erroring on an unknown name — with a copy-pasteable service
call. It also points at the Select source script as the override for the "more than
launching an app" case.

New "Remote command script" subsection: the four variables in a table (command,
num_repeats, delay_secs, hold_secs) with their meanings and defaults, and a
copy-pasteable script that forwards the call to an IR bridge. It states that all four
are always present including defaults, and that unset changes nothing.

Corrected the two claims UNIT A invalidated: the command table no longer says
select_source has no native path, and the paragraph no longer says it is offered only
while a script is configured.

Every fenced YAML block in the README still parses with a real parser (5 now), and
tests/test_readme.py is green.
This commit is contained in:
James Mackay committed 2026-10-11 07:07:36 +01:00
1 parent c3e4c7855c
commit 1c6c223f27
1 file changed
+81 -9
+81 -9
View File
@@ -9,7 +9,9 @@ This is a **Shield-only fork** of [ltomes/ha-nvidia-shield](https://github.com/l
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`).
> **Status:** early fork, actively rebuilt. Releases are date-based
> (`vYYYY.MM.DD`, plus `vYYYY.MM.DD.N` for a second release in the same day) —
> see [Releases](#releases) for how a push becomes one.
> Expect rough edges until the MVP phases land. The build-out plan is in
> [`docs/MVP_PLAN.md`](docs/MVP_PLAN.md); device research is in
> [`docs/RESEARCH_SHIELD.md`](docs/RESEARCH_SHIELD.md).
@@ -286,7 +288,8 @@ helper the flow calls is a coroutine and its dedup only runs when awaited.
transport on or off
- **Shield address / ADB port** — the Shield's IP, and the ADB port if you
changed it from 5555
- **Command scripts** — one optional script per command; see below
- **Command scripts** — one optional script per command, plus one for the remote
entity; see below
### Command scripts (per-command overrides)
@@ -301,13 +304,14 @@ command**:
| `volume_up`, `volume_down` | volume step | — |
| `volume_set` | absolute volume (there is no native path — the protocol has VOLUME_UP/DOWN/MUTE only) | `level` |
| `volume_mute` | mute/unmute | `is_volume_muted` |
| `select_source` | source selection (no native path) | `app_name` |
| `select_source` | source selection (the app list drives it natively; a script overrides) | `app_name` |
A command with a script calls the script **instead of** the protocol/ADB path, never
both. Left unset — the default — every command behaves exactly as it did before, and
clearing a selector on the Configure page restores that. `volume_set` and
`select_source` only appear as services while their script is configured, because
there is nothing native to fall back on.
clearing a selector on the Configure page restores that. Two of the seven appear as
services only when there is something to do: `volume_set`, which has no native path at
all, and `select_source`, which is offered once the integration has sources to offer
(the app list below) — or a script.
The scripts are ordinary Home Assistant scripts. This block covers all three awkward
cases: a speaker switch owning the volume, an AVR owning the input, and a mute that
@@ -350,9 +354,77 @@ Then set `script.shield_volume` as **Volume set script**, `script.shield_source`
**Select source script** and so on on the Configure page. Scripts are set there, not
in the YAML seed above — the seed only carries the address and the transport choice.
A script that fails surfaces as an error on the service call that triggered it (the
command is not retried over protocol/ADB), because a silent no-op is the one outcome
that leaves you guessing.
A script that fails surfaces as a translated error on the service call that triggered
it (the command is not retried over protocol/ADB), because a silent no-op is the one
outcome that leaves you guessing.
### Sources (the app list in a dropdown)
The media player's source list is your **Apps** map — the same map the Browse tree and
app-name resolution use. With no map configured it falls back to a small built-in list
(TiviMate, Wholphin, Netflix, YouTube), so a universal-media-player card always has
something to show:
```yaml
# a media-player card, or anything that reads source_list
type: media-control
entity: media_player.living_room_shield
```
- **`source_list`** — the app names. They come from the map (in the order it lists
them), so editing the map renames the dropdown entries.
- **`source`** — the app currently on screen, resolved exactly like the Current App
sensor: your map first, then the cached device label, then the raw package.
- **`media_player.select_source`** — picks one **by name** and launches it over the
protocol, the same path `play_media` uses for apps. A raw package id works too (that
is what the Browse tree publishes), names match case-insensitively, and a name that
is not in the list is an error rather than a silent no-op:
```yaml
action: media_player.select_source
target:
entity_id: media_player.living_room_shield
data:
source: TiviMate
```
Selecting a source is sometimes more than launching an app — an AVR input, a speaker
switch. That is what the **Select source script** above is for: with one configured it
replaces the native launch entirely.
### Remote command script
`remote.send_command` sends protocol keys: repeats, long presses (`START_LONG`/
`END_LONG`) and inter-repeat delays. Some setups need that call to go somewhere else —
an IR bridge, a macro, a second device — so one optional **Remote command script**
replaces the whole key path when it is set. It receives the service's own parameters,
named as they are on the service:
| Variable | Meaning |
| --- | --- |
| `command` | the list of key commands as submitted, e.g. `["HOME", "KEYCODE_DPAD_CENTER"]` |
| `num_repeats` | how many times to send them (default `1`) |
| `delay_secs` | the delay between repeats in seconds (default `0.0`) |
| `hold_secs` | the requested long-press duration (default `0.0`) — the script owns the key semantics, so it decides what "hold" means |
```yaml
script:
shield_remote: # select as "Remote command script"
alias: Shield remote (IR bridge)
sequence:
- action: remote.send_command
target:
entity_id: remote.living_room_bridge
data:
command: "{{ command }}" # a list: pass it through
num_repeats: "{{ num_repeats }}"
delay_secs: "{{ delay_secs }}"
hold_secs: "{{ hold_secs }}"
```
All four variables are always present, including their defaults, so a script can rely
on the shape. Unset — the default — nothing changes: keys go out over the protocol
exactly as before.
## Entities