mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 13:02:59 +00:00
* fix(install): exclude rpi-rgb-led-matrix from permission normalization The permission normalization step in first_time_install.sh was running chmod 644 on all files, which stripped executable bits from compiled library files (librgbmatrix.so.1) after make build-python created them. This caused LED panels to not work after fresh installation until users manually ran chmod on the rpi-rgb-led-matrix-master directory. Fixes #224 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(install): resolve install script issues and speed up web UI startup Issues addressed: - Remove redundant python3-pillow from apt (Debian maps it to python3-pil) - Only upgrade pip, not setuptools/wheel (they conflict with apt versions) - Remove separate apt numpy install (pip handles it from requirements.txt) - Install web interface deps during first-time setup, not on every startup - Add marker file (.web_deps_installed) to skip redundant pip installs - Add user-friendly message about wait time after installation The web UI was taking 30-60+ seconds to start because it ran pip install on every startup. Now it only installs dependencies on first run. Fixes #208 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(install): prevent duplicate web dependency installation Step 7 was installing web dependencies again even though they were already installed in Step 5. Now Step 7 checks for the .web_deps_installed marker file and skips the installation if it already exists. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(install): only create web deps marker on successful install The .web_deps_installed marker file should only be created when pip install actually succeeds. Previously it was created regardless of the pip exit status, which could cause subsequent runs to skip installing missing dependencies. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Chuck <chuck@example.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
125 lines
6.1 KiB
Python
125 lines
6.1 KiB
Python
import json
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
# Get project root directory (parent of scripts/utils/)
|
|
PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
CONFIG_FILE = os.path.join(PROJECT_DIR, 'config', 'config.json')
|
|
WEB_INTERFACE_SCRIPT = os.path.join(PROJECT_DIR, 'web_interface', 'start.py')
|
|
# Marker file created by first_time_install.sh to indicate dependencies are installed
|
|
DEPS_MARKER = os.path.join(PROJECT_DIR, '.web_deps_installed')
|
|
|
|
|
|
def dependencies_installed():
|
|
"""Check if dependencies were installed during first-time setup."""
|
|
return os.path.exists(DEPS_MARKER)
|
|
|
|
def install_dependencies():
|
|
"""Install required dependencies using system Python."""
|
|
print("Installing dependencies...")
|
|
try:
|
|
requirements_file = os.path.join(PROJECT_DIR, 'web_interface', 'requirements.txt')
|
|
# Use --ignore-installed to handle system packages (like psutil) that can't be uninstalled
|
|
# This allows pip to install even if a system package version conflicts
|
|
result = subprocess.run([
|
|
sys.executable, '-m', 'pip', 'install', '--break-system-packages', '--ignore-installed', '-r', requirements_file
|
|
], capture_output=True, text=True)
|
|
|
|
if result.returncode != 0:
|
|
# Check if the error is just about psutil version conflict
|
|
if 'psutil' in result.stderr.lower() and ('uninstall' in result.stderr.lower() or 'cannot uninstall' in result.stderr.lower()):
|
|
print("Warning: psutil version conflict detected (system package vs requirements).")
|
|
print("Attempting to install other dependencies without psutil...")
|
|
# Try installing without psutil
|
|
with open(requirements_file, 'r') as f:
|
|
lines = f.readlines()
|
|
# Filter out psutil line
|
|
filtered_lines = [line for line in lines if 'psutil' not in line.lower()]
|
|
temp_reqs = os.path.join(PROJECT_DIR, 'web_interface', 'requirements_temp.txt')
|
|
with open(temp_reqs, 'w') as f:
|
|
f.writelines(filtered_lines)
|
|
try:
|
|
subprocess.check_call([
|
|
sys.executable, '-m', 'pip', 'install', '--break-system-packages', '--ignore-installed', '-r', temp_reqs
|
|
])
|
|
print("Dependencies installed successfully (psutil skipped - using system version)")
|
|
finally:
|
|
if os.path.exists(temp_reqs):
|
|
os.remove(temp_reqs)
|
|
else:
|
|
# Re-raise the error if it's not about psutil
|
|
print(f"Failed to install dependencies: {result.stderr}")
|
|
return False
|
|
else:
|
|
print("Dependencies installed successfully")
|
|
|
|
# Install rgbmatrix module from local source (optional - not required for web interface)
|
|
print("Installing rgbmatrix module (optional)...")
|
|
rgbmatrix_path = Path(PROJECT_DIR) / 'rpi-rgb-led-matrix-master' / 'bindings' / 'python'
|
|
if rgbmatrix_path.exists():
|
|
try:
|
|
subprocess.check_call([
|
|
sys.executable, '-m', 'pip', 'install', '--break-system-packages', '-e', str(rgbmatrix_path)
|
|
], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
print("rgbmatrix module installed successfully")
|
|
except subprocess.CalledProcessError:
|
|
print("Warning: rgbmatrix module installation failed (not required for web interface, continuing...)")
|
|
else:
|
|
print("rgbmatrix module path not found (not required for web interface, continuing...)")
|
|
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"Failed to install dependencies: {e}")
|
|
return False
|
|
|
|
def main():
|
|
try:
|
|
with open(CONFIG_FILE, 'r') as f:
|
|
config_data = json.load(f)
|
|
except FileNotFoundError:
|
|
print(f"Config file {CONFIG_FILE} not found. Web interface will not start.")
|
|
sys.exit(0) # Exit gracefully, don't start
|
|
except Exception as e:
|
|
print(f"Error reading config file {CONFIG_FILE}: {e}. Web interface will not start.")
|
|
sys.exit(1) # Exit with error, service might restart depending on config
|
|
|
|
autostart_enabled = config_data.get("web_display_autostart", False)
|
|
|
|
# Handle both boolean True and string "on"/"true" values
|
|
is_enabled = (autostart_enabled is True) or (isinstance(autostart_enabled, str) and autostart_enabled.lower() in ("on", "true", "yes", "1"))
|
|
|
|
if is_enabled:
|
|
print("Configuration 'web_display_autostart' is enabled. Starting web interface...")
|
|
|
|
# Only install dependencies if not already done during first-time setup
|
|
if not dependencies_installed():
|
|
print("First run detected: Installing dependencies...")
|
|
if not install_dependencies():
|
|
print("Failed to install dependencies. Exiting.")
|
|
sys.exit(1)
|
|
# Create marker file after successful install
|
|
Path(DEPS_MARKER).touch()
|
|
print("Dependencies installed and marker file created.")
|
|
else:
|
|
print("Dependencies already installed (marker file found). Skipping installation.")
|
|
|
|
try:
|
|
# Replace the current process with web_interface.py using system Python
|
|
# This is important for systemd to correctly manage the web server process.
|
|
# Ensure PYTHONPATH is set correctly if web_interface.py has relative imports to src
|
|
# The WorkingDirectory in systemd service should handle this for web_interface.py
|
|
print(f"Launching web interface v3: {sys.executable} {WEB_INTERFACE_SCRIPT}")
|
|
os.execvp(sys.executable, [sys.executable, WEB_INTERFACE_SCRIPT])
|
|
except Exception as e:
|
|
print(f"Failed to exec web interface: {e}")
|
|
sys.exit(1) # Failed to start
|
|
else:
|
|
print("Configuration 'web_display_autostart' is false or not set. Web interface will not be started.")
|
|
sys.exit(0) # Exit gracefully, service considered successful
|
|
|
|
if __name__ == '__main__':
|
|
main()
|
|
|