From edc66183c3d493ec984a9e2a2adf9e422eb72c3d Mon Sep 17 00:00:00 2001 From: imonlinux <39863321+imonlinux@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:40:16 -0800 Subject: [PATCH] Update config.py Added a new ButtonConfig dataclass: enabled: bool = False pin: int = 17 (BCM pin for the button) long_press_seconds: float = 1.0 Extended the main Config dataclass with a button: ButtonConfig field. Updated load_config_from_json() to construct button_config from the "button" section in config.json. This allows enabling/disabling the button, changing the GPIO pin, and tuning the long-press threshold (and optional poll interval) without code changes. --- linux_voice_assistant/config.py | 37 ++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/linux_voice_assistant/config.py b/linux_voice_assistant/config.py index 74e453b..ce5bf5c 100644 --- a/linux_voice_assistant/config.py +++ b/linux_voice_assistant/config.py @@ -5,6 +5,9 @@ from dataclasses import dataclass, field from pathlib import Path from typing import Dict, List, Optional +import logging +_LOGGER = logging.getLogger(__name__) + # ----------------------------------------------------------------------------- # Configuration Dataclasses # ----------------------------------------------------------------------------- @@ -16,6 +19,7 @@ class AudioConfig: input_block_size: int = 1024 output_device: Optional[str] = None + @dataclass class WakeWordConfig: """Settings for wake word detection.""" @@ -25,12 +29,14 @@ class WakeWordConfig: refractory_seconds: float = 2.0 download_dir: str = "local" + @dataclass class ESPHomeConfig: """Settings for the ESPHome API server.""" host: str = "0.0.0.0" port: int = 6053 + @dataclass class LedConfig: """Settings for the LED strip.""" @@ -38,7 +44,8 @@ class LedConfig: interface: str = "spi" clock_pin: int = 13 data_pin: int = 12 - num_leds: int = 3 # Note: This will be overridden by 'preferences.json' if it exists + num_leds: int = 3 # Note: overridden by 'preferences.json' if it exists + @dataclass class MqttConfig: @@ -49,6 +56,17 @@ class MqttConfig: username: Optional[str] = None password: Optional[str] = None + +@dataclass +class ButtonConfig: + """Settings for a hardware momentary button (e.g. ReSpeaker 2-Mic HAT).""" + enabled: bool = False + # BCM GPIO pin number for the button input. + pin: int = 17 + # Press duration (in seconds) to be considered a "long press". + long_press_seconds: float = 1.0 + + @dataclass class AppConfig: """General application settings.""" @@ -58,6 +76,7 @@ class AppConfig: preferences_file: str = "preferences.json" debug: bool = False + @dataclass class Config: """Main configuration object.""" @@ -67,6 +86,7 @@ class Config: esphome: ESPHomeConfig = field(default_factory=ESPHomeConfig) led: LedConfig = field(default_factory=LedConfig) mqtt: MqttConfig = field(default_factory=MqttConfig) + button: ButtonConfig = field(default_factory=ButtonConfig) # ----------------------------------------------------------------------------- # Helper Function @@ -74,7 +94,7 @@ class Config: def load_config_from_json(config_path: Path) -> Config: """Loads configuration from a JSON file and populates dataclasses.""" - + # --- Step 1: Load raw JSON data --- try: with open(config_path, "r", encoding="utf-8") as f: @@ -88,15 +108,18 @@ def load_config_from_json(config_path: Path) -> Config: # --- Step 2: Create config objects from raw data --- if "app" not in raw_data: - raise ValueError("Configuration file must contain an 'app' section with a 'name'.") - + raise ValueError( + "Configuration file must contain an 'app' section with a 'name'." + ) + app_config = AppConfig(**raw_data.get("app", {})) audio_config = AudioConfig(**raw_data.get("audio", {})) wake_word_config = WakeWordConfig(**raw_data.get("wake_word", {})) esphome_config = ESPHomeConfig(**raw_data.get("esphome", {})) led_config = LedConfig(**raw_data.get("led", {})) mqtt_config = MqttConfig(**raw_data.get("mqtt", {})) - + button_config = ButtonConfig(**raw_data.get("button", {})) + # --- Step 3: Set MQTT 'enabled' flag --- if mqtt_config.host: mqtt_config.enabled = True @@ -109,7 +132,5 @@ def load_config_from_json(config_path: Path) -> Config: esphome=esphome_config, led=led_config, mqtt=mqtt_config, + button=button_config, ) - -import logging -_LOGGER = logging.getLogger(__name__)