Pause Wyoming satellite on mute (#108322)

Pause satellite on mute
pull/108750/head
Michael Hansen 2024-01-23 19:37:25 -06:00 committed by GitHub
parent d8a1c58b12
commit cffd95a015
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 41 additions and 9 deletions

View File

@ -6,6 +6,6 @@
"dependencies": ["assist_pipeline"], "dependencies": ["assist_pipeline"],
"documentation": "https://www.home-assistant.io/integrations/wyoming", "documentation": "https://www.home-assistant.io/integrations/wyoming",
"iot_class": "local_push", "iot_class": "local_push",
"requirements": ["wyoming==1.5.0"], "requirements": ["wyoming==1.5.2"],
"zeroconf": ["_wyoming._tcp.local."] "zeroconf": ["_wyoming._tcp.local."]
} }

View File

@ -12,7 +12,7 @@ from wyoming.client import AsyncTcpClient
from wyoming.error import Error from wyoming.error import Error
from wyoming.ping import Ping, Pong from wyoming.ping import Ping, Pong
from wyoming.pipeline import PipelineStage, RunPipeline from wyoming.pipeline import PipelineStage, RunPipeline
from wyoming.satellite import RunSatellite from wyoming.satellite import PauseSatellite, RunSatellite
from wyoming.tts import Synthesize, SynthesizeVoice from wyoming.tts import Synthesize, SynthesizeVoice
from wyoming.vad import VoiceStarted, VoiceStopped from wyoming.vad import VoiceStarted, VoiceStopped
from wyoming.wake import Detect, Detection from wyoming.wake import Detect, Detection
@ -76,6 +76,7 @@ class WyomingSatellite:
try: try:
# Check if satellite has been muted # Check if satellite has been muted
while self.device.is_muted: while self.device.is_muted:
_LOGGER.debug("Satellite is muted")
await self.on_muted() await self.on_muted()
if not self.is_running: if not self.is_running:
# Satellite was stopped while waiting to be unmuted # Satellite was stopped while waiting to be unmuted
@ -86,15 +87,23 @@ class WyomingSatellite:
except asyncio.CancelledError: except asyncio.CancelledError:
raise # don't restart raise # don't restart
except Exception: # pylint: disable=broad-exception-caught except Exception: # pylint: disable=broad-exception-caught
# Ensure sensor is off (before restart)
self.device.set_is_active(False)
# Wait to restart
await self.on_restart() await self.on_restart()
finally: finally:
# Ensure sensor is off # Ensure sensor is off (before stop)
self.device.set_is_active(False) self.device.set_is_active(False)
await self.on_stopped() await self.on_stopped()
def stop(self) -> None: def stop(self) -> None:
"""Signal satellite task to stop running.""" """Signal satellite task to stop running."""
# Tell satellite to stop running
self._send_pause()
# Stop task loop
self.is_running = False self.is_running = False
# Unblock waiting for unmuted # Unblock waiting for unmuted
@ -103,7 +112,7 @@ class WyomingSatellite:
async def on_restart(self) -> None: async def on_restart(self) -> None:
"""Block until pipeline loop will be restarted.""" """Block until pipeline loop will be restarted."""
_LOGGER.warning( _LOGGER.warning(
"Unexpected error running satellite. Restarting in %s second(s)", "Satellite has been disconnected. Reconnecting in %s second(s)",
_RECONNECT_SECONDS, _RECONNECT_SECONDS,
) )
await asyncio.sleep(_RESTART_SECONDS) await asyncio.sleep(_RESTART_SECONDS)
@ -126,12 +135,23 @@ class WyomingSatellite:
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
def _send_pause(self) -> None:
"""Send a pause message to satellite."""
if self._client is not None:
self.hass.async_create_background_task(
self._client.write_event(PauseSatellite().event()),
"pause satellite",
)
def _muted_changed(self) -> None: def _muted_changed(self) -> None:
"""Run when device muted status changes.""" """Run when device muted status changes."""
if self.device.is_muted: if self.device.is_muted:
# Cancel any running pipeline # Cancel any running pipeline
self._audio_queue.put_nowait(None) self._audio_queue.put_nowait(None)
# Send pause event so satellite can react immediately
self._send_pause()
self._muted_changed_event.set() self._muted_changed_event.set()
self._muted_changed_event.clear() self._muted_changed_event.clear()
@ -149,16 +169,18 @@ class WyomingSatellite:
async def _connect_and_loop(self) -> None: async def _connect_and_loop(self) -> None:
"""Connect to satellite and run pipelines until an error occurs.""" """Connect to satellite and run pipelines until an error occurs."""
self.device.set_is_active(False)
while self.is_running and (not self.device.is_muted): while self.is_running and (not self.device.is_muted):
try: try:
await self._connect() await self._connect()
break break
except ConnectionError: except ConnectionError:
self._client = None # client is not valid
await self.on_reconnect() await self.on_reconnect()
assert self._client is not None if self._client is None:
return
_LOGGER.debug("Connected to satellite") _LOGGER.debug("Connected to satellite")
if (not self.is_running) or self.device.is_muted: if (not self.is_running) or self.device.is_muted:

View File

@ -2825,7 +2825,7 @@ wled==0.17.0
wolf-smartset==0.1.11 wolf-smartset==0.1.11
# homeassistant.components.wyoming # homeassistant.components.wyoming
wyoming==1.5.0 wyoming==1.5.2
# homeassistant.components.xbox # homeassistant.components.xbox
xbox-webapi==2.0.11 xbox-webapi==2.0.11

View File

@ -2148,7 +2148,7 @@ wled==0.17.0
wolf-smartset==0.1.11 wolf-smartset==0.1.11
# homeassistant.components.wyoming # homeassistant.components.wyoming
wyoming==1.5.0 wyoming==1.5.2
# homeassistant.components.xbox # homeassistant.components.xbox
xbox-webapi==2.0.11 xbox-webapi==2.0.11

View File

@ -35,8 +35,10 @@ STT_INFO = Info(
installed=True, installed=True,
attribution=TEST_ATTR, attribution=TEST_ATTR,
languages=["en-US"], languages=["en-US"],
version=None,
) )
], ],
version=None,
) )
] ]
) )
@ -55,8 +57,10 @@ TTS_INFO = Info(
attribution=TEST_ATTR, attribution=TEST_ATTR,
languages=["en-US"], languages=["en-US"],
speakers=[TtsVoiceSpeaker(name="Test Speaker")], speakers=[TtsVoiceSpeaker(name="Test Speaker")],
version=None,
) )
], ],
version=None,
) )
] ]
) )
@ -74,8 +78,10 @@ WAKE_WORD_INFO = Info(
installed=True, installed=True,
attribution=TEST_ATTR, attribution=TEST_ATTR,
languages=["en-US"], languages=["en-US"],
version=None,
) )
], ],
version=None,
) )
] ]
) )
@ -86,6 +92,7 @@ SATELLITE_INFO = Info(
installed=True, installed=True,
attribution=TEST_ATTR, attribution=TEST_ATTR,
area="Office", area="Office",
version=None,
) )
) )
EMPTY_INFO = Info() EMPTY_INFO = Info()

View File

@ -188,6 +188,7 @@ async def test_dynamic_wake_word_info(
installed=True, installed=True,
attribution=TEST_ATTR, attribution=TEST_ATTR,
languages=[], languages=[],
version=None,
), ),
WakeModel( WakeModel(
name="ww2", name="ww2",
@ -195,8 +196,10 @@ async def test_dynamic_wake_word_info(
installed=True, installed=True,
attribution=TEST_ATTR, attribution=TEST_ATTR,
languages=[], languages=[],
version=None,
), ),
], ],
version=None,
) )
] ]
) )