F-A (HIGH): _user_schema_dict re-declared vol.Optional(CONF_ADB_HOST) /
CONF_PROTOCOL_HOST inside `if "host" in defaults:` — a no-op, because
voluptuous keys compare by field name and the first (defaultless) key object
survives. The discovered address therefore never reached the form, and the
user submitted a blank host. The host keys are now declared WITH default=host
(_host_field_key), so a discovery-driven user step arrives pre-filled.
F-A2: a discovery-driven user step says the address is known
("{discovery_note}Discovered Shield at <host> — its address is already filled
in below. ") through description_placeholders, and the no_state_source
re-render keeps the prefill instead of rebuilding a blank schema.
F-D: the ADB port is declared with default=DEFAULT_ADB_PORT (5555), and a YAML
seed's port hint is carried into the form instead of being flattened to 5555.
The seed host now feeds _seed_host (same prefill, no discovery claim).
Reproduce-through-test: tests/voluptuous_mirror.py mirrors the real
voluptuous.Marker key contract (hash/eq by field name, default=UNDEFINED when
omitted), because voluptuous is not installed in either CI variant and the old
bare-key stubs could not tell a schema WITH a default from one without. The
pre-t33 discovery assertion only checked the stored attribute and stayed green
while the form rendered blank; it now reads the schema keys and fails on the
pre-fix code (8 tests reproduced red locally).
Verified: uvx --with pytest-asyncio pytest tests -q → 242 passed, 1 skipped;
uvx ruff check custom_components tests → clean.
152 lines
8.6 KiB
JSON
152 lines
8.6 KiB
JSON
{
|
|
"config": {
|
|
"step": {
|
|
"user": {
|
|
"title": "NVIDIA Shield",
|
|
"description": "{discovery_note}Set up your NVIDIA Shield. Link the Android TV remote, Jellyfin, receiver, and power monitoring.",
|
|
"data": {
|
|
"name": "Device Name",
|
|
"androidtv_entity": "The media_player entity from the Android TV Remote integration. Optional for standalone setups that pair with the Nvidia Remote Protocol instead.",
|
|
"jellyfin_entity": "Jellyfin Media Player",
|
|
"receiver_entity": "Receiver",
|
|
"receiver_input": "Receiver Input",
|
|
"power_entity": "Power Switch",
|
|
"adb_enabled": "Enable ADB Media Session",
|
|
"adb_store_app_info": "Show App Media Info",
|
|
"adb_host": "ADB Host",
|
|
"adb_port": "ADB Port",
|
|
"protocol_enabled": "Pair with Nvidia Remote Protocol",
|
|
"protocol_host": "Protocol Host"
|
|
},
|
|
"data_description": {
|
|
"androidtv_entity": "The media_player entity from the Android TV Remote integration.",
|
|
"jellyfin_entity": "The Jellyfin media_player for this device. Leave blank to auto-detect.",
|
|
"receiver_entity": "The receiver this device is connected to.",
|
|
"receiver_input": "Which input on the receiver (e.g. 'Shield').",
|
|
"power_entity": "Smart plug switch for reliable on/off detection.",
|
|
"adb_enabled": "Use ADB to read what's playing from any app (NewPipe, Spotify, etc.). Requires ADB debugging enabled on the Shield.",
|
|
"adb_store_app_info": "Show title and artist from non-Jellyfin apps. Disable to only show the app name (privacy mode).",
|
|
"adb_host": "Override the ADB host IP. Leave blank to auto-detect from the Android TV entity \u2014 pre-filled automatically when the Shield was discovered.",
|
|
"adb_port": "ADB port number. Default is 5555.",
|
|
"protocol_enabled": "Adds the all-in-one remote-protocol transport (power/availability/app push and volume readout). Adds a PIN pairing step; the Shield shows the code.",
|
|
"protocol_host": "Override the protocol host IP. Leave blank to auto-detect (same fallback as the ADB host) \u2014 pre-filled automatically on discovery."
|
|
}
|
|
},
|
|
"adb_pair": {
|
|
"title": "Pair ADB",
|
|
"description": "On the Shield, go to Settings > Developer options and enable Network debugging. Then click Submit. You will see a prompt on the Shield to allow the connection -- approve it. If the connection fails, click Submit to try again."
|
|
},
|
|
"protocol_pair": {
|
|
"title": "Pair Remote Protocol",
|
|
"description": "The Shield is now showing a pairing code. Enter it here. Click Submit to confirm.",
|
|
"data": {
|
|
"pairing_code": "Pairing code shown on the Shield"
|
|
}
|
|
},
|
|
"reauth_confirm": {
|
|
"title": "Re-pair Nvidia Shield",
|
|
"description": "The Shield reset to factory settings, so the saved certificate is no longer trusted. A pairing code will be shown on the Shield."
|
|
}
|
|
},
|
|
"error": {
|
|
"adb_failed": "Could not connect via ADB. Make sure Network debugging is enabled on the Shield and you approved the connection prompt. Click Submit to try again.",
|
|
"adb_no_host": "Could not determine the Shield's IP address. Set the ADB Host field on the previous step.",
|
|
"protocol_no_host": "Could not determine the Shield's IP address. Set the Protocol Host or ADB Host field.",
|
|
"protocol_invalid_code": "Pairing has not started or the code is empty. Click Submit to retry.",
|
|
"protocol_pair_failed": "The Shield rejected that pairing code. Click Submit to try again.",
|
|
"no_state_source": "No state source selected. Provide at least one of: the Android TV Remote entity, the Nvidia Remote Protocol pairing, or ADB media-session mode (enable ADB and set the ADB Host).",
|
|
"invalid_app_map": "Each line must be package=name with a non-empty package (no spaces) and a non-empty name \u2014 e.g. ar.tvplayer.tv=TiviMate.",
|
|
"invalid_digit_delay": "The digit delay must be between 0.05 and 1.0 seconds."
|
|
},
|
|
"abort": {
|
|
"already_configured": "This Shield entity is already configured.",
|
|
"reauth_successful": "Re-paired successfully.",
|
|
"reauth_entry_missing": "This entry no longer exists.",
|
|
"zeroconf_no_host": "The discovery event carried no usable address.",
|
|
"yaml_seed_only": {},
|
|
"yaml_seed": {
|
|
"title": "YAML succeeded earlier",
|
|
"message": "The configuration.yaml nvidia_shield block is seed-only: it starts the standard interactive flow. Removing the YAML block creates or deletes nothing."
|
|
}
|
|
}
|
|
},
|
|
"options": {
|
|
"step": {
|
|
"init": {
|
|
"title": "NVIDIA Shield Settings",
|
|
"description": "Configure linked devices and monitoring.",
|
|
"data": {
|
|
"jellyfin_entity": "Jellyfin Media Player",
|
|
"receiver_entity": "Receiver",
|
|
"receiver_input": "Receiver Input",
|
|
"power_entity": "Power Switch",
|
|
"adb_enabled": "Enable ADB Media Session",
|
|
"adb_store_app_info": "Show App Media Info",
|
|
"adb_host": "ADB Host",
|
|
"adb_port": "ADB Port",
|
|
"app_name_map": "Apps name/icon map",
|
|
"adb_command_enabled": "Enable raw ADB shell service",
|
|
"channel_digit_delay": "Channel digit delay (seconds)",
|
|
"channel_send_enter": "Send ENTER after channel digits",
|
|
"logcat_events": "Live events push (logcat)"
|
|
},
|
|
"data_description": {
|
|
"jellyfin_entity": "The Jellyfin media_player for this device. Session stream info is read from the HA Jellyfin integration's existing coordinator \u2014 no extra config needed.",
|
|
"receiver_entity": "The receiver this device is connected to.",
|
|
"receiver_input": "Which input on the receiver.",
|
|
"power_entity": "Smart plug switch for reliable on/off detection.",
|
|
"adb_enabled": "Use ADB to read now-playing from any app. Requires ADB debugging on the Shield.",
|
|
"adb_store_app_info": "Show title and artist from non-Jellyfin apps. Disable for privacy.",
|
|
"adb_host": "IP address for ADB connection. Leave blank to auto-detect from the Android TV Remote integration.",
|
|
"adb_port": "ADB port (default 5555).",
|
|
"app_name_map": "One entry per line, package=name (e.g. ar.tvplayer.tv=TiviMate). The friendly name resolves after the Android TV Remote entity and the protocol push; icons follow the media image lookup by name. Leave blank to clear.",
|
|
"adb_command_enabled": "Adds the nvidia_shield.adb_command service (raw ADB shell over the persistent connection). Security-relevant: leave off unless you need it \u2014 it is the same opt-in posture as the core androidtv integration.",
|
|
"channel_digit_delay": "Pause between the channel digits entered via play_media(channel) \u2014 0.05 to 1.0 seconds (default 0.1, matching the validated behavior).",
|
|
"channel_send_enter": "Optionally presses ENTER after the last digit (protocol key, then the ADB keyevent fallback). Off by default \u2014 matches TiviMate's validated behavior.",
|
|
"logcat_events": "Instant app-open detection via a dedicated logcat stream (AdbDevice.streaming_shell). Default off \u2014 watchdog polling keeps the state honest either way; if the stream fails repeatedly the integration disables it for the session and falls back to polling. Flip on and report stability on your device."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"services": {
|
|
"adb_command": {
|
|
"name": "ADB command",
|
|
"description": "Send a raw ADB shell command to the persistent connection of an Nvidia Shield entry (option-gated use).",
|
|
"fields": {
|
|
"command": {
|
|
"name": "Command",
|
|
"description": "The shell command to run on the device."
|
|
},
|
|
"entity_id": {
|
|
"name": "Entity",
|
|
"description": "The Nvidia Shield media player to target."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"exceptions": {
|
|
"invalid_command": {
|
|
"title": "Empty command",
|
|
"message": "The command field is empty \u2014 nothing was sent."
|
|
},
|
|
"unsupported_target": {
|
|
"title": "Unsupported entity for adb_command",
|
|
"message": "{entity_id} is not an adb_command participant (its entry must enable the adb_command_enabled option) \u2014 command not sent."
|
|
},
|
|
"adb_unavailable": {
|
|
"title": "ADB unavailable",
|
|
"message": "The ADB connection of {entity_id} is down \u2014 command not sent."
|
|
}
|
|
},
|
|
"entity": {
|
|
"sensor": {
|
|
"current_app": {
|
|
"name": "Current app"
|
|
},
|
|
"now_playing": {
|
|
"name": "Now playing"
|
|
}
|
|
}
|
|
}
|
|
}
|