Update __main__.py
Extended Preferences loading to initialize and backfill a new alarm_duration_seconds field (default 0). Added a set_alarm_duration event handler to MicMuteHandler which: validates and normalizes the duration value, updates state.preferences.alarm_duration_seconds, persists the updated preferences to disk. Kept the existing “single writer” pattern (MicMuteHandler) for preferences/state updates.
This commit is contained in:
@@ -48,7 +48,7 @@ class MediaPlayers:
|
||||
tts: MpvMediaPlayer
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Mic Mute Handler
|
||||
# Mic Mute / Preferences Handler
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
class MicMuteHandler(EventHandler):
|
||||
@@ -98,6 +98,45 @@ class MicMuteHandler(EventHandler):
|
||||
self.state.preferences.num_leds = num_leds
|
||||
self.state.save_preferences()
|
||||
|
||||
@subscribe
|
||||
def set_alarm_duration(self, data: dict):
|
||||
"""
|
||||
Event handler to save alarm_duration_seconds to preferences.
|
||||
|
||||
Expected payload from MQTT controller:
|
||||
{ "alarm_duration_seconds": <int> }
|
||||
|
||||
Semantics:
|
||||
0 -> infinite alarm (only stop via Stop wake word / wake word logic)
|
||||
>0 -> auto-stop alarm after N seconds (plus Stop wake word support)
|
||||
"""
|
||||
duration = data.get("alarm_duration_seconds")
|
||||
if duration is None:
|
||||
return
|
||||
|
||||
try:
|
||||
duration = int(duration)
|
||||
except (TypeError, ValueError):
|
||||
_LOGGER.warning(
|
||||
"Invalid alarm_duration_seconds value received: %r", duration
|
||||
)
|
||||
return
|
||||
|
||||
if duration < 0:
|
||||
_LOGGER.warning(
|
||||
"Negative alarm_duration_seconds (%d) is not allowed; ignoring",
|
||||
duration,
|
||||
)
|
||||
return
|
||||
|
||||
current = getattr(self.state.preferences, "alarm_duration_seconds", 0)
|
||||
if current != duration:
|
||||
_LOGGER.debug(
|
||||
"Updating alarm_duration_seconds: %s -> %s", current, duration
|
||||
)
|
||||
self.state.preferences.alarm_duration_seconds = duration
|
||||
self.state.save_preferences()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main Application
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -166,7 +205,10 @@ def _init_basics() -> Tuple[Config, asyncio.AbstractEventLoop, EventBus]:
|
||||
for idx, mic in enumerate(sc.all_microphones(include_loopback=False)):
|
||||
print(f"[{idx}]", mic.name)
|
||||
except Exception as e:
|
||||
_LOGGER.error("Error listing input devices (ensure audio backend is working): %s", e)
|
||||
_LOGGER.error(
|
||||
"Error listing input devices (ensure audio backend is working): %s",
|
||||
e,
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
if args.list_output_devices:
|
||||
@@ -210,7 +252,13 @@ def _load_preferences(config: Config) -> Preferences:
|
||||
else:
|
||||
preferences = Preferences()
|
||||
|
||||
preferences.num_leds = getattr(preferences, 'num_leds', config.led.num_leds)
|
||||
# Backwards-compatible defaults / migrations
|
||||
preferences.num_leds = getattr(preferences, "num_leds", config.led.num_leds)
|
||||
# New: default alarm_duration_seconds, 0 = infinite until Stop/wake word
|
||||
preferences.alarm_duration_seconds = getattr(
|
||||
preferences, "alarm_duration_seconds", 0
|
||||
)
|
||||
|
||||
return preferences
|
||||
|
||||
def _get_microphone(config: Config):
|
||||
@@ -294,17 +342,21 @@ def _load_wake_words(config: Config, preferences: Preferences) -> WakeWordData:
|
||||
|
||||
return WakeWordData(available, models, active, stop_model)
|
||||
|
||||
def _init_media_players(loop: asyncio.AbstractEventLoop, config: Config, preferences: Preferences) -> MediaPlayers:
|
||||
def _init_media_players(
|
||||
loop: asyncio.AbstractEventLoop,
|
||||
config: Config,
|
||||
preferences: Preferences,
|
||||
) -> MediaPlayers:
|
||||
"""Initializes the music and TTS media players."""
|
||||
music_player = MpvMediaPlayer(
|
||||
loop=loop,
|
||||
device=config.audio.output_device,
|
||||
initial_volume=preferences.volume_level
|
||||
initial_volume=preferences.volume_level,
|
||||
)
|
||||
tts_player = MpvMediaPlayer(
|
||||
loop=loop,
|
||||
device=config.audio.output_device,
|
||||
initial_volume=preferences.volume_level
|
||||
initial_volume=preferences.volume_level,
|
||||
)
|
||||
return MediaPlayers(music=music_player, tts=tts_player)
|
||||
|
||||
@@ -377,13 +429,15 @@ async def _run_server(state: ServerState, config: Config):
|
||||
server = await state.loop.create_server(
|
||||
lambda: VoiceSatelliteProtocol(state),
|
||||
host=config.esphome.host,
|
||||
port=config.esphome.port
|
||||
port=config.esphome.port,
|
||||
)
|
||||
discovery = HomeAssistantZeroconf(port=config.esphome.port, name=config.app.name)
|
||||
await discovery.register_server()
|
||||
|
||||
async with server:
|
||||
_LOGGER.info("Server started (host=%s, port=%s)", config.esphome.host, config.esphome.port)
|
||||
_LOGGER.info(
|
||||
"Server started (host=%s, port=%s)", config.esphome.host, config.esphome.port
|
||||
)
|
||||
await server.serve_forever()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user