Commit Graph
33 Commits
Author SHA1 Message Date
d1f5761f75 Restore stop word sensitivity from preferences on startup (#394)
* Restore stop word sensitivity from preferences on startup

The Home Assistant number entity persists preferences.stop_word_sensitivity
whenever it changes, but nothing ever read it back. main() did not pass
stop_word_threshold when constructing ServerState, so it always took the
dataclass default of 0.5, and lowering the sensitivity in Home Assistant
silently reverted at the next restart.

volume and mic_volume are restored at startup, and the two wake word
sensitivities are restored when wake models load. Only the stop word was
missed, so the block that syncs all three sensitivity entities back to Home
Assistant was pushing a default it had never loaded.

Restored alongside volume and clamped the same way. The resolution lives in a
small helper so it can be covered by tests.

* Move the threshold helper to models.py so tests do not import __main__

CI has no PulseAudio daemon. Importing linux_voice_assistant.__main__ pulls in
`import soundcard as sc`, and soundcard/pulseaudio.py instantiates _PulseAudio()
at module scope, which asserts on a live connection. So the four new tests
failed on the runner while passing locally, where a daemon happens to be
running.

That is also why no other test in the suite imports __main__, and why the
existing tests in test_main.py re-implement the logic they check rather than
calling it.

initial_stop_word_threshold() now lives in models.py, which owns both fields it
resolves between: Preferences.stop_word_sensitivity and
ServerState.stop_word_threshold. It imports cleanly, test_models.py already
imports it, and the reference to the ServerState default becomes local.

Behaviour is unchanged. Verified by reproducing the CI environment locally with
PULSE_SERVER pointed at a nonexistent socket: 4 failed before, 298 pass after.

---------

Co-authored-by: ryan felder <7475484+ryanfelder@users.noreply.github.com>
Co-authored-by: Omar Amin <65174210+omaramin-2000@users.noreply.github.com>
2026-08-18 02:07:33 +03:00
Omar Amin 8303a96279 Fix peripheral volume_muted state (#403)
Enable updating the `volume_muted` status when muting/unmuting the media player volume, and improve its tracking.
2026-08-17 20:23:16 +03:00
Willian WangandFlorian Asche a66c0e4f28 feat: add --listen-during-wake-sound argument (#273)
* feat: add --listen-during-wake-sound argument

---------

Co-authored-by: Florian Asche <github@florian-asche.de>
2026-07-18 19:16:11 +02:00
d811ae75d4 Broadcast entity state to all API clients; don't desync on a second connection (#329)
The ESPHome API server delivered asynchronous entity-state changes to a single
connection (the entity's `server`), which every new connection reassigns. A
second API client — a diagnostic tool, a second dashboard, or Home Assistant's
own overlapping reconnect — therefore stole state delivery, leaving Home
Assistant stuck on a stale state (e.g. `media_player` showing `playing` after
playback had finished). `connection_lost` also stopped the shared music/TTS
players for *any* dropped connection.

- models.py: add a per-server connection registry and a `broadcast()` helper.
- satellite.py: register/deregister connections in connection_made/_lost; only
  stop shared playback when the last client disconnects; handle the standard
  `SubscribeStatesRequest` by replaying current entity state to the subscriber.
- entity.py: push playback-completion state via broadcast to all clients.

Co-authored-by: Omar Amin <65174210+omaramin-2000@users.noreply.github.com>
Co-authored-by: Florian Asche <github@florian-asche.de>
2026-07-15 19:11:54 +02:00
Omar Amin 2d460b6728 Leds and buttons events (#266)
Use events and commands to control custom onboard leds and buttons. Can be used to communicate with an external Python script via a WebSocket API running in a container alongside LVA.
2026-07-03 19:58:45 +03:00
Omar Amin 1d84fa0898 Add delay to continue conversation before listening (#342)
Add a configurable amount of delay (defaulting to 0.5s) after the TTS playback is finished to avoid the mic to capture the end of response during start/continue conversation.

Fixes #313
2026-06-19 22:47:01 +03:00
Omar Amin eb29a00386 Enable dual audio input channel (#334)
This PR adds the ability to choose the microphone stream that works best with a particular STT engine using the new dual audio input channel feature.
2026-06-19 02:46:02 +03:00
Omar Amin 3ea32895ee Wake word sensitivity (#207)
## Summary
- Introduces configurable wake word and stop word sensitivity
- Adds UI-controllable thresholds for wake word detection
- Refactors wake word loading and handling logic
- Improves audio preprocessing and runtime behavior

## Key Features
- Per-wake-word sensitivity configuration (Wake Word 1 & 2)
- Configurable stop word sensitivity
- Fine-grained numeric control (0.0 – 1.0, step 0.001)
- Sensitivity values exposed as Number Entities for Home Assistant
- Persistent storage of user-defined sensitivity values

## Wake Word Handling
- Support for model-specific default thresholds (`probability_cutoff`)
- Automatic fallback to defaults if no user value is set
- Separate thresholds for:
  - Wake Word 1
  - Wake Word 2
  - Stop Word
- Unified handling for MicroWakeWord and OpenWakeWord models

## UI / API Integration
- Adds new Home Assistant entities:
  - `WakeWord1SensitivityNumberEntity`
  - `WakeWord2SensitivityNumberEntity`
  - `StopWordSensitivityNumberEntity`
- Entities support:
  - Live updates
  - Persistence via preferences
  - Synchronization with runtime state
- Pushes updated values to Home Assistant on startup

## Refactoring
- Extracted wake word logic into `wake_word.py`
  - Model discovery
  - Model loading
  - Stop word handling
- Simplified `__main__.py` by delegating wake word responsibilities
- Improved separation between configuration and runtime state

## Additional Changes
- Improved debug logging across initialization and runtime

## Impact
- Enables fine-tuning of wake word detection accuracy
- Reduces false positives and missed triggers
- Improves usability via UI-based configuration
- Provides better flexibility across different environments and microphones
2026-04-21 02:04:11 +02:00
Omar Amin c284806b73 Add the ability to control microphone volume (#287)
Control microphone volume via UI in device page. Set to the maximum by default and saved in preferences to restore upon restarts.
2026-04-10 01:33:34 +02:00
aryanhasgithub 4ee7bb04bc Add support for WebRTC Auto Gain and Noise Suppression (#250)
## WebRTC Auto Gain & Noise Suppression
 
This PR adds support for WebRTC Auto Gain and Noise Suppression as previously implemented in the Wyoming Satellite project.
 
### What's New
 
Two new entities have been created a number slider for gain and another one for noise suppression. The processing happens inside of the `webrtc.py` file and is implemented in the `__main__.py` file's `process_audio` function. The slider for gain has a limit of 0-31 and noise suppression has a limit of 0-4.
 
The Auto Gain and Noise Suppression persist through restarts and are saved as preferences. The values are dynamically chnged without needing a restart.
 
CLI flags called `--mic-auto-gain` and `--mic-noise-suppression` have also been added.
 
>  When both values are 0, WebRTC processing is bypassed entirely with no performance overhead.

Closes #25 
 
### Testing
 
When saving the audio recorded by LVA there is a noticeable increase. The following two files have been recorded with similar audio being played through them with these results (Gain-31 and NS-4):
 
| Metric | With AGC+NS | Without |
|---|---|---|
| Max amplitude | 0.329 | 0.054 |
| RMS amplitude | 0.008905 | 0.002862 |
| Volume adjustment needed | 3.034x | 13.479x |
| Rough frequency | 916 Hz | 705 Hz |
2026-04-09 00:43:11 +02:00
JaminandFlorian Asche 7732be0de8 Output only satellite (#182)
Output only satellite for nodes with only speakers and no microphone.
Supports announcements and playing media only.

---------

Co-authored-by: Florian Asche <github@florian-asche.de>
2026-03-31 01:56:16 +02:00
Omar Amin 4194aa42ec Add maximum seconds for ringing timer (#261)
Auto stop ringing timer if the determined time (default 15 mins) has passed without manually stopping. This max time can be modified using the command `--timer-max-ring-seconds`.
2026-03-25 01:46:53 +02:00
Florian Asche 1fc29241b4 Add linting scripts and pipeline (#201)
* Add linting scripts and pipeline
2026-03-05 01:58:39 +01:00
Omar Amin c81a707c6a Enhance volume persistence with logging
Add logging for volume persistence and conditionally skip saving if unchanged.
2026-02-22 00:43:32 +02:00
Omar Amin 981a786a46 Merge branch 'main' into Volume-Persistence-Across-Restarts 2026-02-21 22:19:05 +02:00
Florian Asche 7de510cb1f Add version and hash to docker container (#167)
* Add version and git hash to image
* Add version reporting to HA via api
2026-02-21 20:38:46 +01:00
Omar Amin ac69618d29 Add volume handling to Preferences and persistence method
Added volume attribute to Preferences and implemented persist_volume method to save normalized media volume.
2026-02-21 16:25:16 +02:00
Florian Asche 4052daae01 hotfix for mac-detection and various variable names (#139)
* Change Client-Name: The client name inside LVA is not capable of having spaces in the name. Fixed the example.
* Add first version of Docker-Compose for developers
* Add variable for network-interface and auto detection by default
* Added autodetection for the MAC-Address based on the detected or specified network-interface.
* Switched from listening on all IP-Addresses to the IP of the default interface, usually u set the correct network-interface and it will automatically detect the right IP-Address.
* Added missing variables, fixed variables names
* Fixed not working variables for example sound-files.
* Moved the auto-name creation from shell to python. The name is no longer mandatory, it will be generated if no name is given.
2026-02-13 19:50:20 +01:00
Jamin Hitchcock 4b7242a1d3 Fix some format and linting issues 2026-02-02 04:15:17 +00:00
Omar Amin 8ca997c7d3 Merge branch 'OHF-Voice:main' into Add-mute/unmute-sounds 2026-01-21 01:45:28 +02:00
Omar Amin 1b7c8ca639 Add mute switch functionality 2026-01-21 00:04:40 +02:00
Omar Amin 016f2005e2 Update models.py 2025-12-17 16:03:39 +02:00
Omar Amin acdeda866b Merge branch 'main' into main 2025-11-12 15:44:11 +02:00
Michael Hansen 716fe30c29 Support custom/external wake words 2025-11-11 15:19:15 -06:00
Omar Amin 67cd15790b Update models.py 2025-11-05 16:45:56 +02:00
Omar Amin f81a119239 Add thinking sound switch 2025-11-05 16:23:25 +02:00
Omar Amin 29a3202189 Merge branch 'OHF-Voice:main' into main 2025-11-04 15:46:29 +02:00
Michael Hansen 72c8f021c8 Use pymicro-wakeword and pyopen-wakeword libraries 2025-10-16 14:29:48 -05:00
Omar Amin 0ade1a0e27 Add processing_sound 2025-09-26 21:53:28 +03:00
Michael Hansen d5300ae694 Support openWakeWord 2025-09-16 15:05:18 -05:00
Michael Hansen e26864a191 Support multiple wake words 2025-09-15 11:29:28 -05:00
Michael Hansen 2c937e3cb3 Save preferences to JSON file 2025-09-15 11:06:09 -05:00
Michael Hansen ea901a1c14 Small refactor 2025-09-15 10:43:51 -05:00