From 2b01e48d1b2cc5ef911e57e59c3996561f9ac8f2 Mon Sep 17 00:00:00 2001 From: Kevin Ahrendt Date: Mon, 10 Aug 2026 07:46:59 -0400 Subject: [PATCH] [voice_assistant] Do not enable internal-only wake words on request The disable-all loop iterates get_wake_words(), which filters out internal-only models, but the enable path uses get_model_by_id(), which does not. Enabling one from a set_configuration request left it active with no way to turn it off short of a reboot. --- esphome/components/voice_assistant/voice_assistant.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/esphome/components/voice_assistant/voice_assistant.cpp b/esphome/components/voice_assistant/voice_assistant.cpp index 00986eca07..7181b65181 100644 --- a/esphome/components/voice_assistant/voice_assistant.cpp +++ b/esphome/components/voice_assistant/voice_assistant.cpp @@ -1120,6 +1120,12 @@ void VoiceAssistant::on_set_configuration(const std::vector &active for (const auto &ww_id : active_wake_words) { // Already loaded (compiled or previously downloaded) enable() persists the state. if (auto *model = this->micro_wake_word_->get_model_by_id(ww_id)) { + // get_model_by_id does not filter internal-only models, but the disable loop above iterates + // get_wake_words(), which does. Enabling one here would leave it stuck on until a reboot. + if (model->get_internal_only()) { + ESP_LOGW(TAG, "Ignoring request to enable internal-only wake word: %s", ww_id.c_str()); + continue; + } model->enable(); ESP_LOGD(TAG, "Enabled wake word: %s (id=%s)", model->get_wake_word().c_str(), model->get_id().c_str()); continue;