From a9cf822136be56cbb6defbbfee74b076ae0afcaf Mon Sep 17 00:00:00 2001 From: imonlinux <39863321+imonlinux@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:43:08 -0800 Subject: [PATCH] Update satellite.py Extended the satellite state machine with a manual wake entrypoint: Added manual_wakeup(self, phrase: str = "button"): Mirrors the semantics of wakeup(), but does not require a wake-word model instance. Respects the current state: only triggers from STARTING or IDLE. If a timer alarm is ringing, calls the existing _stop_timer_alarm(...) instead of starting a new conversation (consistent with wake-word behavior). Otherwise calls a shared helper _start_conversation(phrase). Introduced _start_conversation(wake_word_phrase: str) to encapsulate: Sending VoiceAssistantRequest(start=True, wake_word_phrase=...), Transitioning to LISTENING, Setting _is_streaming_audio = True, Playing the configured wakeup_sound via tts_player. Kept prior timer/alarm logic intact (including auto stop and Stop wake word behavior), so the button integrates cleanly with existing timer and TTS flows. --- linux_voice_assistant/satellite.py | 32 ++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/linux_voice_assistant/satellite.py b/linux_voice_assistant/satellite.py index 9ddd34d..9c929a0 100644 --- a/linux_voice_assistant/satellite.py +++ b/linux_voice_assistant/satellite.py @@ -478,6 +478,16 @@ class VoiceSatelliteProtocol(APIServer): ) self._stop_timer_alarm("auto_timeout") + def _start_conversation(self, wake_word_phrase: str) -> None: + """Shared helper to start a new conversation run.""" + _LOGGER.debug("Starting conversation: %s", wake_word_phrase) + self.send_messages( + [VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)] + ) + self._set_state(SatelliteState.LISTENING) + self._is_streaming_audio = True + self.state.tts_player.play(self.state.wakeup_sound) + def wakeup(self, wake_word: Union[MicroWakeWord, OpenWakeWord]) -> None: if self._state not in (SatelliteState.IDLE, SatelliteState.STARTING): # Existing behavior: ignore wakeup in other states. @@ -491,12 +501,22 @@ class VoiceSatelliteProtocol(APIServer): wake_word_phrase = getattr(wake_word, "wake_word", "wake word") _LOGGER.debug("Detected wake word: %s", wake_word_phrase) - self.send_messages( - [VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)] - ) - self._set_state(SatelliteState.LISTENING) - self._is_streaming_audio = True - self.state.tts_player.play(self.state.wakeup_sound) + self._start_conversation(wake_word_phrase) + + def manual_wakeup(self, phrase: str = "button") -> None: + """ + Manual wakeup entrypoint (e.g. hardware button) that behaves like a + wake word, but without requiring a wake-word model instance. + """ + if self._state not in (SatelliteState.IDLE, SatelliteState.STARTING): + return + + if self._timer_finished: + self._stop_timer_alarm("button") + return + + _LOGGER.debug("Manual wakeup triggered: %s", phrase) + self._start_conversation(phrase) def stop(self) -> None: """