From e78a8727b2841080d63f55fa09695a580deb99e4 Mon Sep 17 00:00:00 2001 From: Pi User Date: Fri, 3 Oct 2025 20:19:55 +1300 Subject: [PATCH] Add .env support for transport and sound device configuration - Add python-dotenv support to control_server.py and sound.py - Load TRANSPORT from environment variable (default: spi) - Load AUDIO_INPUT_DEVICE from environment variable (default: 7) - Load all port configurations from environment variables - Update .env.example with comprehensive configuration options - Create .env file with sensible defaults for Pi - Transport, sound device, and network settings now configurable via .env --- .env | 9 +++++++++ .env.example | 27 +++++++++++++++++++++++++++ Pipfile | 1 + Pipfile.lock | 10 +++++++++- src/control_server.py | 16 +++++++++++----- src/sound.py | 16 +++++++++++----- 6 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 0000000..9585771 --- /dev/null +++ b/.env @@ -0,0 +1,9 @@ +# Lighting Controller Configuration +CONTROL_SERVER_URI=ws://localhost:8765 +CONTROL_SERVER_PORT=8765 +TRANSPORT=spi +AUDIO_INPUT_DEVICE=7 +MIDI_TCP_HOST=127.0.0.1 +MIDI_TCP_PORT=65432 +SOUND_CONTROL_HOST=127.0.0.1 +SOUND_CONTROL_PORT=65433 diff --git a/.env.example b/.env.example index e2c4e6a..fd8bdb2 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,8 @@ # Lighting Controller Configuration +# ============================== +# WebSocket Configuration +# ============================== # WebSocket URI for the control server # Used by UI client and test scripts to connect to the control server # @@ -11,3 +14,27 @@ CONTROL_SERVER_URI=ws://10.42.0.1:8765 # # For custom IP (if your Pi has a different address): # CONTROL_SERVER_URI=ws://YOUR_PI_IP:8765 + +# Control server WebSocket port +CONTROL_SERVER_PORT=8765 + +# ============================== +# Transport Configuration +# ============================== +# Transport method for LED communication +# Options: spi, websocket +TRANSPORT=spi + +# ============================== +# Sound Detection Configuration +# ============================== +# Audio input device index (use sound.py to list available devices) +AUDIO_INPUT_DEVICE=7 + +# MIDI TCP configuration +MIDI_TCP_HOST=127.0.0.1 +MIDI_TCP_PORT=65432 + +# Sound control server configuration +SOUND_CONTROL_HOST=127.0.0.1 +SOUND_CONTROL_PORT=65433 diff --git a/Pipfile b/Pipfile index dac6148..00389d9 100644 --- a/Pipfile +++ b/Pipfile @@ -13,6 +13,7 @@ python-rtmidi = "*" pyaudio = "*" aubio = "*" websocket-client = "*" +python-dotenv = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 11581ae..502087f 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3f3ca9af45dd4382aac3c649ae11cefbe97059ad14f40172735213c4919baada" + "sha256": "db66b0f2b4e51e5a0bc2edc0d89af123c03928c72add32c16ba955eaefc34da7" }, "pipfile-spec": 6, "requires": { @@ -162,6 +162,14 @@ "index": "pypi", "version": "==0.2.14" }, + "python-dotenv": { + "hashes": [ + "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", + "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab" + ], + "index": "pypi", + "version": "==1.1.1" + }, "python-rtmidi": { "hashes": [ "sha256:052c89933cae4fca354012d8ca7248f4f9e1e3f062471409d48415a7f7d7e59e", diff --git a/src/control_server.py b/src/control_server.py index 5688e58..4beeb07 100644 --- a/src/control_server.py +++ b/src/control_server.py @@ -13,17 +13,22 @@ import socket import threading import time import argparse +import os +from dotenv import load_dotenv from bar_config import LED_BAR_NAMES, DEFAULT_BAR_SETTINGS from color_utils import adjust_brightness from networking import SPIClient, WebSocketClient +# Load environment variables from .env file +load_dotenv() + # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # Configuration -CONTROL_SERVER_PORT = 8765 -SOUND_CONTROL_HOST = "127.0.0.1" -SOUND_CONTROL_PORT = 65433 +CONTROL_SERVER_PORT = int(os.getenv("CONTROL_SERVER_PORT", "8765")) +SOUND_CONTROL_HOST = os.getenv("SOUND_CONTROL_HOST", "127.0.0.1") +SOUND_CONTROL_PORT = int(os.getenv("SOUND_CONTROL_PORT", "65433")) # Pattern name mapping for shorter JSON payloads PATTERN_NAMES = { @@ -463,11 +468,12 @@ def parse_arguments(): # Transport selection transport_group = parser.add_argument_group("Transport Options") + default_transport = os.getenv("TRANSPORT", "spi") transport_group.add_argument( "--transport", choices=["spi", "websocket"], - default="spi", - help="Transport method for LED communication (default: spi)" + default=default_transport, + help=f"Transport method for LED communication (default from .env or {default_transport})" ) # Control options diff --git a/src/sound.py b/src/sound.py index 6e4643e..664ecf5 100644 --- a/src/sound.py +++ b/src/sound.py @@ -11,18 +11,23 @@ import time import logging # Added logging import import asyncio # Re-added asyncio import import threading # Added threading for control server +import os +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() # Configure logging DEBUG_MODE = True # Set to False for INFO level logging logging.basicConfig(level=logging.DEBUG if DEBUG_MODE else logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') # TCP Server Configuration (assuming midi.py runs this) -MIDI_TCP_HOST = "127.0.0.1" -MIDI_TCP_PORT = 65432 +MIDI_TCP_HOST = os.getenv("MIDI_TCP_HOST", "127.0.0.1") +MIDI_TCP_PORT = int(os.getenv("MIDI_TCP_PORT", "65432")) # Sound Control Server Configuration (for midi.py to control sound.py) -SOUND_CONTROL_HOST = "127.0.0.1" -SOUND_CONTROL_PORT = 65433 +SOUND_CONTROL_HOST = os.getenv("SOUND_CONTROL_HOST", "127.0.0.1") +SOUND_CONTROL_PORT = int(os.getenv("SOUND_CONTROL_PORT", "65433")) class SoundBeatDetector: def __init__(self, tcp_host: str, tcp_port: int, *, input_device: int | None = None): @@ -35,7 +40,8 @@ class SoundBeatDetector: self.bufferSize = 512 self.windowSizeMultiple = 2 - self.audioInputDeviceIndex = 7 if input_device is None else int(input_device) + default_device = int(os.getenv("AUDIO_INPUT_DEVICE", "7")) + self.audioInputDeviceIndex = default_device if input_device is None else int(input_device) self.audioInputChannels = 1 self.pa = pyaudio.PyAudio()