diff --git a/README.md b/README.md index ec9cb03..f83e540 100644 --- a/README.md +++ b/README.md @@ -32,9 +32,10 @@ A Home Assistant integration exposes devices as entities for smart home automati - Color strip sources: audio-reactive, pattern generator, composite layering, audio-to-color mapping - Pattern templates with customizable effects -### Audio Integration (Windows) +### Audio Integration - Multichannel audio capture from any system device (input or loopback) +- WASAPI engine on Windows, Sounddevice (PortAudio) engine on Linux/macOS - Per-channel mono extraction - Audio-reactive color strip sources driven by frequency analysis @@ -64,7 +65,18 @@ A Home Assistant integration exposes devices as entities for smart home automati - Python 3.11+ (or Docker) - A supported LED device on the local network or connected via USB -- Windows for GPU-accelerated capture engines and audio capture; Linux/macOS supported via MSS +- Windows, Linux, or macOS — all core features work cross-platform + +### Platform Notes + +| Feature | Windows | Linux / macOS | +| ------- | ------- | ------------- | +| Screen capture | DXCam, BetterCam, WGC, MSS | MSS | +| Audio capture | WASAPI, Sounddevice | Sounddevice (PulseAudio/PipeWire) | +| GPU monitoring | NVIDIA (pynvml) | NVIDIA (pynvml) | +| Android capture | Scrcpy (ADB) | Scrcpy (ADB) | +| Monitor names | Friendly names (WMI) | Generic ("Display 0") | +| Profile conditions | Process/window detection | Not yet implemented | ## Quick Start @@ -104,7 +116,7 @@ wled-screen-controller/ │ │ │ ├── capture/ # Screen capture, calibration, pixel processing │ │ │ ├── capture_engines/ # MSS, DXCam, BetterCam, WGC, Scrcpy backends │ │ │ ├── devices/ # WLED, Adalight, AmbileD, DDP clients -│ │ │ ├── audio/ # Audio capture (Windows) +│ │ │ ├── audio/ # Audio capture engines │ │ │ ├── filters/ # Post-processing filter pipeline │ │ │ ├── processing/ # Stream orchestration and target processors │ │ │ └── profiles/ # Condition-based profile automation diff --git a/server/pyproject.toml b/server/pyproject.toml index 7d91085..62a114f 100644 --- a/server/pyproject.toml +++ b/server/pyproject.toml @@ -41,7 +41,7 @@ dependencies = [ "zeroconf>=0.131.0", "pyserial>=3.5", "psutil>=5.9.0", - "nvidia-ml-py>=12.0.0; sys_platform == 'win32'", + "nvidia-ml-py>=12.0.0", "PyAudioWPatch>=0.2.12; sys_platform == 'win32'", "sounddevice>=0.5", ] diff --git a/server/restart.sh b/server/restart.sh new file mode 100644 index 0000000..6d8a8c1 --- /dev/null +++ b/server/restart.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Restart the WLED Screen Controller server (Linux/macOS) +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Stop any running instance +PIDS=$(pgrep -f 'wled_controller\.main' 2>/dev/null || true) +if [ -n "$PIDS" ]; then + echo "Stopping server (PID $PIDS)..." + pkill -f 'wled_controller\.main' 2>/dev/null || true + sleep 2 +fi + +# Start server detached +echo "Starting server..." +cd "$SCRIPT_DIR" +nohup python -m wled_controller.main > /dev/null 2>&1 & +sleep 3 + +# Verify it's running +NEW_PID=$(pgrep -f 'wled_controller\.main' 2>/dev/null || true) +if [ -n "$NEW_PID" ]; then + echo "Server started (PID $NEW_PID)" +else + echo "WARNING: Server does not appear to be running!" +fi diff --git a/server/src/wled_controller/api/routes/system.py b/server/src/wled_controller/api/routes/system.py index 160779b..e9350f1 100644 --- a/server/src/wled_controller/api/routes/system.py +++ b/server/src/wled_controller/api/routes/system.py @@ -273,19 +273,26 @@ STORE_MAP = { "profiles": "profiles_file", } -_RESTART_SCRIPT = Path(__file__).resolve().parents[4] / "restart.ps1" +_SERVER_DIR = Path(__file__).resolve().parents[4] def _schedule_restart() -> None: - """Spawn restart.ps1 after a short delay so the HTTP response completes.""" + """Spawn a restart script after a short delay so the HTTP response completes.""" def _restart(): import time time.sleep(1) - subprocess.Popen( - ["powershell", "-ExecutionPolicy", "Bypass", "-File", str(_RESTART_SCRIPT)], - creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP, - ) + if sys.platform == "win32": + subprocess.Popen( + ["powershell", "-ExecutionPolicy", "Bypass", "-File", + str(_SERVER_DIR / "restart.ps1")], + creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP, + ) + else: + subprocess.Popen( + ["bash", str(_SERVER_DIR / "restart.sh")], + start_new_session=True, + ) threading.Thread(target=_restart, daemon=True).start()