Adds XVF3800-specific initialization flow during controller startup.
Ensures the XVF3800 preflight runs at the right time so audio initialization sees the correct device state.
Imported the new ButtonController.
In _init_controllers():
Instantiated ButtonController when config.button.enabled is True.
Passed loop, event_bus, state, and config.button.
Stored the instance on state.button_controller to keep it alive for the lifetime of the process.
Left the rest of startup orchestration unchanged (audio engine, MQTT, LEDs, etc.), so the button is just an additional input surface plugged into the existing architecture.
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.
File: linux_voice_assistant/__main__.py
In _init_basics(), the --list-output-devices block is updated so that:
It exits with 0 on success.
It exits with 1 only if an exception occurs.
New CLI helpers
Added support for:
script/run --list-input-devices
script/run --list-output-devices
These code paths:
Initialize just enough of the audio stack to enumerate devices.
Print a clean, human-readable list of input/output devices (including PipeWire / PulseAudio virtual devices like Echo-Cancel Source and pipewire/echo-cancel-sink).
Exit cleanly with status 0 instead of trying to start the full LVA process afterward (fixing the previous CalledProcessError when --list-output-devices was used).
Behavior change
__main__.py now treats the “list devices” modes as early-exit utility modes, not “run LVA and then also print devices”.
This makes it practical to use these commands in setup docs and shell scripts.
(Major change) main() function completely refactored into helpers. _init_controllers now handles decoupled initialization. _process_audio loop logic was fixed to correctly initialize wake words on startup.
mic.recorder() loop is now much more robust against OS buffering issue when the microphone is muted and wakewords were detected and processed after unmute.
(Major change) main() function completely refactored into helpers. _init_controllers now handles decoupled initialization. _process_audio loop logic was fixed to correctly initialize wake words on startup.
Replaced sounddevice with soundcard, removed the audio Queue, added the new download directory to the search path, and added the device listing arguments
Removed all argparse.add_argument() calls, except for the new --config flag. The main() function now calls load_config_from_json() at startup. All internal logic now references the config object (e.g., config.app.name) instead of the old args object.
Fix MpvMediaPlayer Race Condition
Goal: The mpv library runs in its own thread. When a track finishes, its callback (_on_idle_active) runs in that thread and tries to modify the satellite's state, creating a race condition. We will fix this by "marshaling" that callback onto the main asyncio loop.
added loop=loop to the MpvMediaPlayer constructors
Adds command-line arguments (--mqtt-host, --mqtt-port, etc., and --num-leds) to configure the MQTT connection and initial LED setup.
Instantiates and starts the MqttController on application startup if an MQTT host is provided.
Includes the MicMuteHandler class, which listens for mute commands, updates the global mic_muted state, and clears the audio queue on unmute to prevent processing stale audio.
Updates the process_audio loop to respect the mic_muted flag.
Implements the core mute functionality.
Adds a new MicMuteHandler class that subscribes to the set_mic_mute event. This handler updates the state.mic_muted flag and publishes secondary mic_muted or mic_unmuted events for LED feedback.
Modifies the process_audio function to check the state.mic_muted flag in its main loop, pausing audio processing when the flag is True.
Modifies the startup sequence to read the volume_level from the loaded preferences.
This saved value is then passed as the initial_volume when creating the music_player and tts_player instances.
Passes the event_bus and loop instances into the ServerState object upon creation.
Adds new command-line arguments (--led-interface, --led-clock-pin, --led-data-pin) to allow the user to select and configure the LED hardware interface at runtime.