Hi all! I had my good friend Gemini help me hack this together so I figured I’d post it here for posterity. I am also using TTMG (GitHub - eslavnov/ttmg_server: Talk To Me Goose Server) for faster responses with no timeouts when using OpenAI as the TTS backend.
substitutions:
name: home-assistant-voice-09a8ec
friendly_name: Home Assistant Voice 09a8ec
packages:
Nabu Casa.Home Assistant Voice PE: github://esphome/home-assistant-voice-pe/home-assistant-voice.yaml
esphome:
name: ${name}
name_add_mac_suffix: false
friendly_name: ${friendly_name}
api:
encryption:
key: SEEKRIT
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
## Talk To Me, Goose!
external_components:
- source:
type: local
path: /config/custom_components/DEVICEID/
media_player:
- platform: speaker
id: !extend external_media_player
files:
# - id: !remove wake_word_triggered_sound
- id: wake_sound_1
file: /config/custom_components/DEVICEID/voice_assistant/wake_sounds/wake_1.flac
- id: wake_sound_2
file: /config/custom_components/DEVICEID/voice_assistant/wake_sounds/wake_2.flac
- id: wake_sound_3
file: /config/custom_components/DEVICEID/voice_assistant/wake_sounds/wake_3.flac
- id: wake_sound_4
file: /config/custom_components/DEVICEID/voice_assistant/wake_sounds/wake_4.flac
- id: wake_sound_5
file: /config/custom_components/DEVICEID/voice_assistant/wake_sounds/wake_5.flac
script:
# Script executed when we want to play sounds on the device.
- id: !remove play_sound
- id: play_sound
parameters:
priority: bool
sound_file: "audio::AudioFile*"
then:
- if:
# --- CORRECTED Condition Syntax ---
condition:
# Use 'lambda:' as the key
lambda: |-
// Compare the passed pointer with the pointer for the original ID
return sound_file == id(wake_word_triggered_sound);
# --- END CORRECTED Condition Syntax ---
then:
# --- Play a RANDOM sound instead ---
- lambda: |-
// Define the vector storing pointers directly
static const std::vector<esphome::audio::AudioFile*> wake_sounds{
id(wake_sound_1),
id(wake_sound_2),
id(wake_sound_3),
id(wake_sound_4),
id(wake_sound_5)
// Add id(wake_sound_N) for all your sounds
};
if (wake_sounds.empty()) {
ESP_LOGW("play_sound_random", "No wake sounds defined in vector!");
return; // Do nothing if no sounds
}
int random_index = random() % wake_sounds.size();
ESP_LOGD("play_sound_random", "Intercepted wake sound request. Playing random index: %d", random_index);
esphome::audio::AudioFile* random_sound = wake_sounds[random_index];
// --- Directly play the random sound ---
if (priority) {
id(external_media_player)
->make_call()
.set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_STOP)
.set_announcement(true)
.perform();
}
if ( (id(external_media_player).state != media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING ) || priority) {
id(external_media_player)
->play_file(random_sound, true, false);
}
else:
# --- Play the requested sound NORMALLY (Original Logic) ---
- lambda: |-
if (priority) {
id(external_media_player)
->make_call()
.set_command(media_player::MediaPlayerCommand::MEDIA_PLAYER_COMMAND_STOP)
.set_announcement(true)
.perform();
}
if ( (id(external_media_player).state != media_player::MediaPlayerState::MEDIA_PLAYER_STATE_ANNOUNCING ) || priority) {
id(external_media_player)
->play_file(sound_file, true, false);
}