Add Linux support: cross-platform restart, nvidia-ml-py dep, README update
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
18
README.md
18
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
|
- Color strip sources: audio-reactive, pattern generator, composite layering, audio-to-color mapping
|
||||||
- Pattern templates with customizable effects
|
- Pattern templates with customizable effects
|
||||||
|
|
||||||
### Audio Integration (Windows)
|
### Audio Integration
|
||||||
|
|
||||||
- Multichannel audio capture from any system device (input or loopback)
|
- Multichannel audio capture from any system device (input or loopback)
|
||||||
|
- WASAPI engine on Windows, Sounddevice (PortAudio) engine on Linux/macOS
|
||||||
- Per-channel mono extraction
|
- Per-channel mono extraction
|
||||||
- Audio-reactive color strip sources driven by frequency analysis
|
- 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)
|
- Python 3.11+ (or Docker)
|
||||||
- A supported LED device on the local network or connected via USB
|
- 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
|
## Quick Start
|
||||||
|
|
||||||
@@ -104,7 +116,7 @@ wled-screen-controller/
|
|||||||
│ │ │ ├── capture/ # Screen capture, calibration, pixel processing
|
│ │ │ ├── capture/ # Screen capture, calibration, pixel processing
|
||||||
│ │ │ ├── capture_engines/ # MSS, DXCam, BetterCam, WGC, Scrcpy backends
|
│ │ │ ├── capture_engines/ # MSS, DXCam, BetterCam, WGC, Scrcpy backends
|
||||||
│ │ │ ├── devices/ # WLED, Adalight, AmbileD, DDP clients
|
│ │ │ ├── devices/ # WLED, Adalight, AmbileD, DDP clients
|
||||||
│ │ │ ├── audio/ # Audio capture (Windows)
|
│ │ │ ├── audio/ # Audio capture engines
|
||||||
│ │ │ ├── filters/ # Post-processing filter pipeline
|
│ │ │ ├── filters/ # Post-processing filter pipeline
|
||||||
│ │ │ ├── processing/ # Stream orchestration and target processors
|
│ │ │ ├── processing/ # Stream orchestration and target processors
|
||||||
│ │ │ └── profiles/ # Condition-based profile automation
|
│ │ │ └── profiles/ # Condition-based profile automation
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ dependencies = [
|
|||||||
"zeroconf>=0.131.0",
|
"zeroconf>=0.131.0",
|
||||||
"pyserial>=3.5",
|
"pyserial>=3.5",
|
||||||
"psutil>=5.9.0",
|
"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'",
|
"PyAudioWPatch>=0.2.12; sys_platform == 'win32'",
|
||||||
"sounddevice>=0.5",
|
"sounddevice>=0.5",
|
||||||
]
|
]
|
||||||
|
|||||||
27
server/restart.sh
Normal file
27
server/restart.sh
Normal file
@@ -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
|
||||||
@@ -273,19 +273,26 @@ STORE_MAP = {
|
|||||||
"profiles": "profiles_file",
|
"profiles": "profiles_file",
|
||||||
}
|
}
|
||||||
|
|
||||||
_RESTART_SCRIPT = Path(__file__).resolve().parents[4] / "restart.ps1"
|
_SERVER_DIR = Path(__file__).resolve().parents[4]
|
||||||
|
|
||||||
|
|
||||||
def _schedule_restart() -> None:
|
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():
|
def _restart():
|
||||||
import time
|
import time
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
if sys.platform == "win32":
|
||||||
subprocess.Popen(
|
subprocess.Popen(
|
||||||
["powershell", "-ExecutionPolicy", "Bypass", "-File", str(_RESTART_SCRIPT)],
|
["powershell", "-ExecutionPolicy", "Bypass", "-File",
|
||||||
|
str(_SERVER_DIR / "restart.ps1")],
|
||||||
creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP,
|
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()
|
threading.Thread(target=_restart, daemon=True).start()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user