feat(config_flow): digit-delay (0.05–1.0 s, invalid input error) + optional send-enter options UI consumed by the §7 channel path; strings/README updated (P5-2.1)

This commit is contained in:
James Mackay committed 2026-10-09 05:55:07 +01:00
1 parent 4661e52041
commit 3d026ae60e
4 files changed
+45 -6

No files matched your search

+8
View File
@@ -84,6 +84,14 @@ 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.
### Channel entry options
The options flow exposes the §7 channel behavior the integration replicates:
the inter-digit **delay** (0.05–1.0 s, default 0.1) and the optional
**ENTER press** after the digits (off by default — TiviMate's validated
behavior). Both are consumed by `play_media` with
`media_content_type: channel`.
### Raw `adb_command` service (opt-in)
When enabled in the integration's options (`adb_command_enabled`, **default
@@ -13,6 +13,7 @@ from .adb_session import ensure_adb_key
from .connection import ShieldConnectionManager
from .const import (
ATTR_MEDIA_DAG_INPUT_MAP,
CHANNEL_DIGIT_DELAY,
CONF_ADB_COMMAND_ENABLED,
CONF_ADB_ENABLED,
CONF_ADB_HOST,
@@ -20,6 +21,8 @@ from .const import (
CONF_ADB_STORE_APP_INFO,
CONF_ANDROIDTV_ENTITY,
CONF_APP_NAME_MAP,
CONF_CHANNEL_DIGIT_DELAY,
CONF_CHANNEL_SEND_ENTER,
CONF_JELLYFIN_ENTITY,
CONF_PAIRING_CODE,
CONF_POWER_ENTITY,
@@ -497,6 +500,16 @@ class NvidiaShieldOptionsFlow(config_entries.OptionsFlow):
"""Single-page options."""
errors = {}
if user_input is not None:
# P5-2: validate the digit delay (0.05–1.0 s, §7 window)
delay = user_input.pop(CONF_CHANNEL_DIGIT_DELAY, None)
if delay is not None:
try:
delay = float(delay)
except (TypeError, ValueError):
errors["base"] = "invalid_digit_delay"
delay = None
if delay is not None and not (0.05 <= delay <= 1.0):
errors["base"] = "invalid_digit_delay"
app_map_text = user_input.pop(CONF_APP_NAME_MAP, None)
if app_map_text is None:
app_map = self._options.get(CONF_APP_NAME_MAP, {})
@@ -507,6 +520,8 @@ class NvidiaShieldOptionsFlow(config_entries.OptionsFlow):
if app_map is None:
errors["base"] = "invalid_app_map"
if not errors:
if delay is not None:
self._options[CONF_CHANNEL_DIGIT_DELAY] = delay
self._options.update(user_input)
self._options[CONF_APP_NAME_MAP] = app_map
return self.async_create_entry(title="", data=self._options)
@@ -537,6 +552,12 @@ class NvidiaShieldOptionsFlow(config_entries.OptionsFlow):
recv_key = vol.Optional(CONF_RECEIVER_ENTITY, default=recv)
schema_dict[recv_key] = sel["receiver"]
# P5-2: channel digit behavior (the user-validated §7 flow)
current_delay = self._options.get(CONF_CHANNEL_DIGIT_DELAY, CHANNEL_DIGIT_DELAY)
schema_dict[vol.Optional(CONF_CHANNEL_DIGIT_DELAY, default=current_delay)] = str
current_enter = self._options.get(CONF_CHANNEL_SEND_ENTER, False)
schema_dict[vol.Optional(CONF_CHANNEL_SEND_ENTER, default=current_enter)] = bool
# P4-2a: the raw adb_command service is opt-in (default off)
current_flag = self._options.get(CONF_ADB_COMMAND_ENABLED, False)
schema_dict[vol.Optional(CONF_ADB_COMMAND_ENABLED, default=current_flag)] = bool
+8 -3
View File
@@ -55,7 +55,8 @@
"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_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.",
@@ -79,7 +80,9 @@
"adb_host": "ADB Host",
"adb_port": "ADB Port",
"app_name_map": "Apps name/icon map",
"adb_command_enabled": "Enable raw ADB shell service"
"adb_command_enabled": "Enable raw ADB shell service",
"channel_digit_delay": "Channel digit delay (seconds)",
"channel_send_enter": "Send ENTER after channel digits"
},
"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.",
@@ -91,7 +94,9 @@
"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."
"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."
}
}
}
@@ -55,7 +55,8 @@
"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_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.",
@@ -79,7 +80,9 @@
"adb_host": "ADB Host",
"adb_port": "ADB Port",
"app_name_map": "Apps name/icon map",
"adb_command_enabled": "Enable raw ADB shell service"
"adb_command_enabled": "Enable raw ADB shell service",
"channel_digit_delay": "Channel digit delay (seconds)",
"channel_send_enter": "Send ENTER after channel digits"
},
"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.",
@@ -91,7 +94,9 @@
"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."
"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."
}
}
}