[voice_assistant] Make TTS playback start timeout configurable (#18707)

Co-authored-by: n-IA-hane <n-IA-hane@users.noreply.github.com>
This commit is contained in:
n-IA-hane
2026-10-13 08:13:26 -10:00
committed by GitHub
co-authored by n-IA-hane
parent 5acbd44067
commit d27ec8ec49
9 changed files with 100 additions and 2 deletions
@@ -0,0 +1,44 @@
"""Test playback timeout C++ generation."""
from collections.abc import Callable
from pathlib import Path
import pytest
@pytest.mark.parametrize("timeout", [None, "2s", "2000ms", "1ms", "10s"])
def test_playback_timeout_codegen(
timeout: str | None,
tmp_path: Path,
generate_main: Callable[[Path], str],
) -> None:
config = tmp_path / "voice_assistant.yaml"
config.write_text(
"""esphome:
name: test-voice-assistant
esp32:
board: esp32dev
framework:
type: esp-idf
wifi:
ssid: test-network
api:
i2s_audio:
i2s_lrclk_pin: GPIO25
i2s_bclk_pin: GPIO26
microphone:
- platform: i2s_audio
id: test_mic
adc_type: external
i2s_din_pin: GPIO34
voice_assistant:
microphone: test_mic
"""
+ (f" tts_playback_start_timeout: {timeout}\n" if timeout else "")
)
main = generate_main(config)
if timeout in (None, "2s", "2000ms"):
assert "set_tts_playback_start_timeout(" not in main
else:
milliseconds = 1 if timeout == "1ms" else 10000
assert f"set_tts_playback_start_timeout({milliseconds});" in main
@@ -55,6 +55,7 @@ voice_assistant:
speaker: va_speaker_id
micro_wake_word: mww_id
conversation_timeout: 60s
tts_playback_start_timeout: 10s
on_listening:
- logger.log: "Voice assistant microphone listening"
on_start:
@@ -36,6 +36,7 @@ voice_assistant:
channels: 0
speaker: va_speaker_id
conversation_timeout: 60s
tts_playback_start_timeout: 10s
on_listening:
- logger.log: "Voice assistant microphone listening"
on_start:
@@ -0,0 +1,35 @@
"""Validate Voice Assistant playback timeout configuration."""
import pytest
from esphome.components import voice_assistant
import esphome.config_validation as cv
from esphome.const import KEY_CORE, KEY_TARGET_PLATFORM
from esphome.core import CORE
@pytest.mark.parametrize(
"value",
["0s", "0ms", {"seconds": 0}, "-1s", "500us", "1ns", "500ns", {"nanoseconds": 1}],
)
def test_playback_timeout_rejects_invalid_duration(value: str | dict[str, int]) -> None:
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: "esp32"}
with pytest.raises(cv.Invalid):
voice_assistant.CONFIG_SCHEMA({"tts_playback_start_timeout": value})
@pytest.mark.parametrize(
"value, milliseconds", [("1ms", 1), ("2s", 2000), ("10s", 10000)]
)
def test_playback_timeout_accepts_positive_milliseconds(
value: str, milliseconds: int
) -> None:
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: "esp32"}
config = voice_assistant.CONFIG_SCHEMA({"tts_playback_start_timeout": value})
assert config["tts_playback_start_timeout"].total_milliseconds == milliseconds
def test_playback_timeout_default_is_two_seconds() -> None:
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: "esp32"}
config = voice_assistant.CONFIG_SCHEMA({})
assert config["tts_playback_start_timeout"].total_milliseconds == 2000