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.
This commit is contained in:
imonlinux
2025-11-29 23:43:08 -08:00
committed by GitHub
parent 0073dc6a23
commit a9cf822136
+26 -6
View File
@@ -478,6 +478,16 @@ class VoiceSatelliteProtocol(APIServer):
) )
self._stop_timer_alarm("auto_timeout") 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: def wakeup(self, wake_word: Union[MicroWakeWord, OpenWakeWord]) -> None:
if self._state not in (SatelliteState.IDLE, SatelliteState.STARTING): if self._state not in (SatelliteState.IDLE, SatelliteState.STARTING):
# Existing behavior: ignore wakeup in other states. # Existing behavior: ignore wakeup in other states.
@@ -491,12 +501,22 @@ class VoiceSatelliteProtocol(APIServer):
wake_word_phrase = getattr(wake_word, "wake_word", "wake word") wake_word_phrase = getattr(wake_word, "wake_word", "wake word")
_LOGGER.debug("Detected wake word: %s", wake_word_phrase) _LOGGER.debug("Detected wake word: %s", wake_word_phrase)
self.send_messages( self._start_conversation(wake_word_phrase)
[VoiceAssistantRequest(start=True, wake_word_phrase=wake_word_phrase)]
) def manual_wakeup(self, phrase: str = "button") -> None:
self._set_state(SatelliteState.LISTENING) """
self._is_streaming_audio = True Manual wakeup entrypoint (e.g. hardware button) that behaves like a
self.state.tts_player.play(self.state.wakeup_sound) 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: def stop(self) -> None:
""" """