Summary
Add USB context manager support and optimize polling interval
Problem
Missing context manager: USB resources could leak on exceptions
Aggressive polling: 100 Hz (10ms) unnecessarily high for human button presses
Changes
Context Manager Support (Critical Fix B)
Added __enter__ and __exit__ methods to XVF3800USBClient class
Enhanced close() with proper null checks and error handling
Enables safe with statement usage
Polling Optimization (Critical Fix C)
Changed default poll_interval_seconds from 0.01 to 0.05 (100 Hz → 20 Hz)
Updated XVF3800ButtonRuntimeConfig dataclass default
Updated fallback default in __init__ constructor
Problem
XVF3800 LED ring worked inconsistently (~50% success rate at startup) due to: 1. Timing race: LED commands sent before WS2812 power (X0D33) enabled 2. Missing context manager: USB resources could leak on exceptions
Changes
Context Manager Support (Critical Fix B)
Added __enter__ and __exit__ methods to _ReSpeaker class
Enhanced close() with proper null checks and error handling
Enables safe with statement usage
LED Power Management (NEW Critical Fix)
Proactive initialization: Enable X0D33 immediately in __init__ before any LED operations
Defensive runtime checks: Added _ensure_led_power() helper method
Power verification: Check X0D33 state before set_effect() and set_ring_colors()
Added 50ms settle time after enabling power
Documentation
Added GPO_WRITE_VALUE and GPO_READ_VALUES to PARAMETERS dict
Added GPO_WS2812_POWER_INDEX constant for clarity
Enhanced inline comments explaining power management
Summary
Add thread-safe locking for wake word reload logic
Problem
Wake word reload logic accessed self.state.wake_words_changed flag without synchronization, creating a potential race condition when wake words are dynamically switched via Home Assistant.
Changes
Added self._wake_words_lock = threading.Lock() in __init__
Wrapped wake word reload block with with self._wake_words_lock: context manager
Ensures atomic read-modify-write of wake_words_changed flag
Impact
Risk: Very low - purely defensive improvement
Benefit: Eliminates race condition in wake word switching
Performance: Negligible overhead (lock only held during reload check)
What this fixes:
On boot, if PipeWire/Pulse starts with the sink at ~40%, LVA now pushes the sink volume to match the persisted LVA volume (0.0–1.0).
When you move the HA media_player volume slider, LVA now updates:
wpctl (PipeWire) if available
pactl (PulseAudio / PipeWire-Pulse) if available
amixer (ALSA) as a fallback
No reboot / alsactl store required — LVA simply re-applies the persisted volume at start.
What this fixes:
On boot, if PipeWire/Pulse starts with the sink at ~40%, LVA now pushes the sink volume to match the persisted LVA volume (0.0–1.0).
When you move the HA media_player volume slider, LVA now updates:
wpctl (PipeWire) if available
pactl (PulseAudio / PipeWire-Pulse) if available
amixer (ALSA) as a fallback
No reboot / alsactl store required — LVA simply re-applies the persisted volume at start.
What this fixes:
On boot, if PipeWire/Pulse starts with the sink at ~40%, LVA now pushes the sink volume to match the persisted LVA volume (0.0–1.0).
When you move the HA media_player volume slider, LVA now updates:
wpctl (PipeWire) if available
pactl (PulseAudio / PipeWire-Pulse) if available
amixer (ALSA) as a fallback
No reboot / alsactl store required — LVA simply re-applies the persisted volume at start.
Updated to align with the new XVF3800 initialization pathway / preflight behavior.
Keeps XVF3800 behavior isolated to XVF3800 mode so other LED backends remain unchanged.
Extends the existing XVF3800 USB control backend beyond LEDs to support startup preflight commands needed for audio reliability.
Implements command execution internally (no reliance on xvf_host.py) using the same USB control-transfer approach already used for LED features.
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.
Added support for the XVF3800 per-LED command LED_RING_COLOR (12-LED ring, 48-byte payload).
Implemented/readied the device control logic so the backend can:
write per-LED frames (set_ring_rgb / set_ring_solid / clear_ring),
detect availability (supports_per_led) and fall back if unsupported.
Improved robustness/diagnostics for USB control transfers (more consistent request composition + debug logging around writes).
Prevented MQTT command/state feedback loops while keeping HA-friendly behavior:
accepts retained /state topics during a short startup bootstrap window to restore last-known settings,
then stops processing /state messages and unsubscribes from .../+/state after bootstrap.
Ensures runtime control is driven only by /set topics, while /state remains publish-only for HA UI synchronization.
Adds explicit logging around bootstrap completion to make startup behavior clear.
Integrated per-LED rendering into the existing effect/state pipeline:
solid/off uses ring frames directly,
blink toggles between frames (color ↔ off),
pulse now rewrites LED_RING_COLOR with scaled RGB per step (instead of relying on global brightness),
spin uses a single “dot” moving around the 12 LEDs.
Ensured the controller uses the XVF3800’s fixed ring size (12) where appropriate.
Fixed the “stuck in Responding” issue by subscribing the voice_idle handler so Idle effects reapply correctly when returning to IDLE.
Keeps all existing DotStar/NeoPixel behavior intact.
Adds a USB-based XVF3800 backend using the legacy LED controls (LED_EFFECT, LED_BRIGHTNESS, LED_SPEED, LED_COLOR).
Plugs it into LedController by treating "led_type": "xvf3800", "interface": "usb" as a new backend.