From bc553b69d6e5c66a5cdc71c7caa97b8da6992468 Mon Sep 17 00:00:00 2001 From: Chuck <33324927+ChuckBuilds@users.noreply.github.com> Date: Tue, 22 Sep 2026 16:15:59 -0400 Subject: [PATCH] chore(scripts): delete unreferenced helper scripts None of these is referenced by an installer, systemd unit, CI workflow, test, the web UI or src/: - utils/cleanup_venv.sh removes venv_web_v2, which nothing creates - utils/clear_python_cache.sh hardcodes ~/LEDMatrix and a .webassets-cache nothing uses - install/migrate_config.sh only copies the template, which the installer and ConfigManager already do - install/debug_install.sh, debug/debug_web_manual.py - diagnose_web_ui.sh and verify_web_ui.sh overlap diagnose_web_interface.sh, which the docs point to - fix_internet_connectivity.sh is iptables-only (stale on nftables) - diagnose_plugin_permissions.sh, dev/validate_python.py - download_nba_logos.py + README_NBA_LOGOS.md: logo_downloader fetches logos on demand - setup_plugin_repos.py linked into the production plugin-repos/ dir; the dev workflow is scripts/dev/dev_plugin_setup.sh, and MULTI_ROOT_WORKSPACE_SETUP.md now uses it Co-Authored-By: Claude Opus 5.5 --- docs/MIGRATION_GUIDE.md | 1 - docs/MULTI_ROOT_WORKSPACE_SETUP.md | 87 +++++----- scripts/README_NBA_LOGOS.md | 120 ------------- scripts/debug/debug_web_manual.py | 96 ---------- scripts/dev/README.md | 6 - scripts/dev/validate_python.py | 95 ---------- scripts/diagnose_plugin_permissions.sh | 171 ------------------ scripts/diagnose_web_ui.sh | 232 ------------------------- scripts/download_nba_logos.py | 98 ----------- scripts/fix_internet_connectivity.sh | 109 ------------ scripts/install/README.md | 3 - scripts/install/debug_install.sh | 85 --------- scripts/install/migrate_config.sh | 43 ----- scripts/setup_plugin_repos.py | 93 ---------- scripts/utils/README.md | 2 - scripts/utils/cleanup_venv.sh | 23 --- scripts/utils/clear_python_cache.sh | 20 --- scripts/verify_web_ui.sh | 164 ----------------- 18 files changed, 41 insertions(+), 1407 deletions(-) delete mode 100644 scripts/README_NBA_LOGOS.md delete mode 100644 scripts/debug/debug_web_manual.py delete mode 100644 scripts/dev/validate_python.py delete mode 100755 scripts/diagnose_plugin_permissions.sh delete mode 100755 scripts/diagnose_web_ui.sh delete mode 100644 scripts/download_nba_logos.py delete mode 100755 scripts/fix_internet_connectivity.sh delete mode 100755 scripts/install/debug_install.sh delete mode 100755 scripts/install/migrate_config.sh delete mode 100755 scripts/setup_plugin_repos.py delete mode 100755 scripts/utils/cleanup_venv.sh delete mode 100755 scripts/utils/clear_python_cache.sh delete mode 100755 scripts/verify_web_ui.sh diff --git a/docs/MIGRATION_GUIDE.md b/docs/MIGRATION_GUIDE.md index c6b17c94..b768c82b 100644 --- a/docs/MIGRATION_GUIDE.md +++ b/docs/MIGRATION_GUIDE.md @@ -19,7 +19,6 @@ All installation scripts have been moved from the project root to `scripts/insta | `install_wifi_monitor.sh` | `scripts/install/install_wifi_monitor.sh` | | `setup_cache.sh` | `scripts/install/setup_cache.sh` | | `configure_web_sudo.sh` | `scripts/install/configure_web_sudo.sh` | -| `migrate_config.sh` | `scripts/install/migrate_config.sh` | #### Permission Fix Scripts diff --git a/docs/MULTI_ROOT_WORKSPACE_SETUP.md b/docs/MULTI_ROOT_WORKSPACE_SETUP.md index 56bbab2f..17e0fe09 100644 --- a/docs/MULTI_ROOT_WORKSPACE_SETUP.md +++ b/docs/MULTI_ROOT_WORKSPACE_SETUP.md @@ -10,11 +10,12 @@ Official plugins live in a single repository, [ledmatrix-plugins](https://github.com/ChuckBuilds/ledmatrix-plugins), with one directory per plugin under `plugins/`. There are no separate per-plugin repositories. For development you clone that monorepo **next to** LEDMatrix -and symlink its plugin directories into LEDMatrix's `plugin-repos/`, which is -where the plugin loader looks by default. +and symlink the plugin directories you are working on into LEDMatrix's +`plugins/` directory with `scripts/dev/dev_plugin_setup.sh`. - ✅ Plugin code stays in the monorepo checkout, with its own git history -- ✅ LEDMatrix discovers the plugins through symlinks in `plugin-repos/` +- ✅ LEDMatrix discovers the plugins through symlinks in `plugins/` + (git-ignored), so the production `plugin-repos/` directory is untouched - ✅ `LEDMatrix.code-workspace` opens both repositories in VS Code/Cursor ## Directory Structure @@ -22,12 +23,11 @@ where the plugin loader looks by default. ```text ~/Github/ ├── LEDMatrix/ # Main project -│ ├── plugin-repos/ # Plugin directory the loader scans -│ │ ├── starlark-apps/ # Bundled with LEDMatrix (tracked in git) -│ │ ├── web-ui-info/ # Bundled with LEDMatrix (tracked in git) -│ │ ├── clock-simple -> ../../ledmatrix-plugins/plugins/clock-simple -│ │ ├── ledmatrix-weather -> ../../ledmatrix-plugins/plugins/ledmatrix-weather +│ ├── plugins/ # Dev plugin directory (git-ignored) +│ │ ├── clock-simple -> ~/Github/ledmatrix-plugins/plugins/clock-simple +│ │ ├── ledmatrix-weather -> ~/Github/ledmatrix-plugins/plugins/ledmatrix-weather │ │ └── ... +│ ├── plugin-repos/ # Default (Plugin Store) plugin directory │ ├── LEDMatrix.code-workspace # Opens LEDMatrix and ../ledmatrix-plugins │ └── ... └── ledmatrix-plugins/ # Plugin monorepo (git repo) @@ -44,61 +44,65 @@ where the plugin loader looks by default. ### 1. The plugin monorepo Clone ledmatrix-plugins into the same parent directory as LEDMatrix (the -scripts below look for `../ledmatrix-plugins` relative to the LEDMatrix -root): +workspace file and `scripts/update_plugin_repos.py` look for +`../ledmatrix-plugins` relative to the LEDMatrix root): ```bash cd ~/Github git clone https://github.com/ChuckBuilds/ledmatrix-plugins.git ``` -### 2. Symlinks in plugin-repos/ +### 2. Symlinks in plugins/ -`scripts/setup_plugin_repos.py` creates one symlink per plugin in -`LEDMatrix/plugin-repos/`, named after the plugin's manifest `id` and pointing -at `../ledmatrix-plugins/plugins/`. +`scripts/dev/dev_plugin_setup.sh link ` creates +`LEDMatrix/plugins/` as a symlink to a plugin directory. Use the +plugin's manifest `id` as the name: that is the name the loader and +`config.json` use, and the script warns when the two differ. ### 3. Multi-root workspace `LEDMatrix.code-workspace` has two roots: LEDMatrix itself and `../ledmatrix-plugins`. -## Setup Scripts +## Setup -### Initial Setup +### Link plugins ```bash cd ~/Github/LEDMatrix -python3 scripts/setup_plugin_repos.py +./scripts/dev/dev_plugin_setup.sh link clock-simple ../ledmatrix-plugins/plugins/clock-simple +./scripts/dev/dev_plugin_setup.sh list # show what is linked ``` -This script: -- Reads each `manifest.json` under `../ledmatrix-plugins/plugins/` -- Creates `plugin-repos/` symlinks (relative) to those directories -- Leaves correct links alone, replaces links that point elsewhere, and skips - (does not overwrite) a real directory of the same name — for example a - plugin you installed from the Plugin Store. Remove that directory first if - you want the linked copy. +If a real (non-symlink) directory of the same name already exists in +`plugins/`, the script offers to back it up and replace it. + +Without a sibling checkout, `./scripts/dev/dev_plugin_setup.sh link-github +` clones the monorepo into `~/.ledmatrix-dev-plugins/` instead and links +the plugin from there. See the +[Plugin Development Guide](PLUGIN_DEVELOPMENT_GUIDE.md). ### Updating Plugins ```bash cd ~/Github/LEDMatrix -python3 scripts/update_plugin_repos.py +python3 scripts/update_plugin_repos.py # git pull in ../ledmatrix-plugins +# or +./scripts/dev/dev_plugin_setup.sh update # git pull in every linked checkout ``` -This runs `git pull` in `../ledmatrix-plugins` and prints the result. The -symlinks pick up the new code; restart the display to load it. +The symlinks pick up the new code; restart the display to load it. ## Configuration -The loader reads plugins from `plugin_system.plugins_directory` in -`config/config.json`. The default is already right for this setup: +The loader scans only `plugin_system.plugins_directory` in +`config/config.json` (default `plugin-repos`). Point it at `plugins` so it +finds the links: ```json { "plugin_system": { - "plugins_directory": "plugin-repos" + "plugins_directory": "plugins" } } ``` @@ -117,7 +121,7 @@ The loader reads plugins from `plugin_system.plugins_directory` in ### Adding New Plugins 1. Create `plugins//` in the monorepo checkout -2. Run `python3 scripts/setup_plugin_repos.py` in LEDMatrix to link it +2. Link it: `./scripts/dev/dev_plugin_setup.sh link ../ledmatrix-plugins/plugins/` ## Troubleshooting @@ -125,30 +129,21 @@ The loader reads plugins from `plugin_system.plugins_directory` in ```bash cd ~/Github/LEDMatrix -ls -la plugin-repos/ # links present and not broken? -python3 scripts/setup_plugin_repos.py # recreate them +ls -la plugins/ # links present and not broken? +./scripts/dev/dev_plugin_setup.sh status # link targets and git state ``` -Also check that `plugin_system.plugins_directory` is `plugin-repos`. - -### "Monorepo plugins directory not found" - -`setup_plugin_repos.py` expects the monorepo at `../ledmatrix-plugins`. Clone -it there (or symlink it there). +Also check that `plugin_system.plugins_directory` is `plugins`. ### Plugin updates not showing -1. Verify the link target: `ls -la plugin-repos/` +1. Verify the link target: `ls -la plugins/` 2. Check that you're editing the monorepo checkout, not a store-installed copy 3. Restart the LEDMatrix service (or `run.py`) ## Notes -- `plugin-repos/` is tracked in git only for the bundled plugins - (`starlark-apps`, `web-ui-info`). The symlinks you create are untracked - files; don't commit them. -- For linking a single plugin into `plugins/` instead (without a sibling - checkout), see `scripts/dev/dev_plugin_setup.sh` in the - [Plugin Development Guide](PLUGIN_DEVELOPMENT_GUIDE.md). +- `plugins/` is git-ignored (except `plugins/.gitkeep`); the symlinks are + never committed. - When changing a plugin in the monorepo, bump its manifest `version` and run `python update_registry.py`, or users won't receive the update. diff --git a/scripts/README_NBA_LOGOS.md b/scripts/README_NBA_LOGOS.md deleted file mode 100644 index 8ae9b496..00000000 --- a/scripts/README_NBA_LOGOS.md +++ /dev/null @@ -1,120 +0,0 @@ -# NBA Logo Downloader - -This script downloads all NBA team logos from the ESPN API and saves -them in the `assets/sports/nba_logos/` directory. - -> **Heads up:** the NBA leaderboard and basketball scoreboards now -> live as plugins in the -> [`ledmatrix-plugins`](https://github.com/ChuckBuilds/ledmatrix-plugins) -> repo (`basketball-scoreboard`, `ledmatrix-leaderboard`). Those -> plugins download the logos they need automatically on first display. -> This standalone script is mainly useful when you want to pre-populate -> the assets directory ahead of time, or for development/debugging. - -All commands below should be run from the LEDMatrix project root. - -## Usage - -### Basic Usage -```bash -python3 scripts/download_nba_logos.py -``` - -### Force Re-download -If you want to re-download all logos (even if they already exist): -```bash -python3 scripts/download_nba_logos.py --force -``` - -### Quiet Mode -Reduce logging output: -```bash -python3 scripts/download_nba_logos.py --quiet -``` - -### Combined Options -```bash -python3 scripts/download_nba_logos.py --force --quiet -``` - -## What It Does - -1. **Fetches NBA Team Data**: Gets the complete list of NBA teams from ESPN API -2. **Downloads Logos**: Downloads each team's logo from ESPN's servers -3. **Saves Locally**: Saves logos as `{team_abbr}.png` in `assets/sports/nba_logos/` -4. **Skips Existing**: By default, skips teams that already have logos -5. **Rate Limiting**: Includes small delays between downloads to be respectful to the API - -## Expected Output - -``` -🏀 Starting NBA logo download... -Target directory: assets/sports/nba_logos/ -Force download: False -✅ NBA logo download complete! -📊 Summary: 30 downloaded, 0 failed -🎉 NBA logos are now ready for use in the leaderboard! -``` - -## File Structure - -After running the script, you'll have: -``` -assets/sports/nba_logos/ -├── ATL.png # Atlanta Hawks -├── BOS.png # Boston Celtics -├── BKN.png # Brooklyn Nets -├── CHA.png # Charlotte Hornets -├── CHI.png # Chicago Bulls -├── CLE.png # Cleveland Cavaliers -├── DAL.png # Dallas Mavericks -├── DEN.png # Denver Nuggets -├── DET.png # Detroit Pistons -├── GSW.png # Golden State Warriors -├── HOU.png # Houston Rockets -├── IND.png # Indiana Pacers -├── LAC.png # LA Clippers -├── LAL.png # Los Angeles Lakers -├── MEM.png # Memphis Grizzlies -├── MIA.png # Miami Heat -├── MIL.png # Milwaukee Bucks -├── MIN.png # Minnesota Timberwolves -├── NOP.png # New Orleans Pelicans -├── NYK.png # New York Knicks -├── OKC.png # Oklahoma City Thunder -├── ORL.png # Orlando Magic -├── PHI.png # Philadelphia 76ers -├── PHX.png # Phoenix Suns -├── POR.png # Portland Trail Blazers -├── SAC.png # Sacramento Kings -├── SAS.png # San Antonio Spurs -├── TOR.png # Toronto Raptors -├── UTA.png # Utah Jazz -└── WAS.png # Washington Wizards -``` - -## Integration with NBA plugins - -Once the logos are in `assets/sports/nba_logos/`, both the -`basketball-scoreboard` and `ledmatrix-leaderboard` plugins will pick -them up automatically and skip their own first-run download. This is -useful if you want to deploy a Pi without internet access to ESPN, or -if you want to preview the display on your dev machine without -waiting for downloads. - -## Troubleshooting - -### "Import error: No module named 'requests'" -Make sure you're running this from the LEDMatrix project directory where all dependencies are installed. - -### "Permission denied" errors -Make sure the script has write permissions to the `assets/sports/nba_logos/` directory. - -### Some logos fail to download -This is normal - some teams might have temporary API issues or the ESPN API might be rate-limiting. The script will continue with the successful downloads. - -## Requirements - -- Python 3.9+ (matches the project's overall minimum) -- `requests` library (already in `requirements.txt`) -- Write access to `assets/sports/nba_logos/` directory diff --git a/scripts/debug/debug_web_manual.py b/scripts/debug/debug_web_manual.py deleted file mode 100644 index 387a4300..00000000 --- a/scripts/debug/debug_web_manual.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env python3 -""" -Web Interface Manual Debug Script -Run this to diagnose why web_interface/start.py isn't working -""" - -import sys -import os -import traceback -from pathlib import Path - -def main(): - print("🔍 LED Matrix Web Interface Debug Tool") - print("=" * 50) - - # Change to project root (two levels up from scripts/debug/) - project_root = Path(__file__).parent.parent.parent.resolve() - os.chdir(project_root) - print(f"📁 Working directory: {os.getcwd()}") - - # Add to Python path - sys.path.insert(0, str(project_root)) - print(f"🔗 Python path includes: {project_root}") - - print("\n1. Testing basic imports...") - try: - import flask - print(f" ✅ Flask: {flask.__version__}") - except ImportError as e: - print(f" ❌ Flask missing: {e}") - return False - - try: - from src.config_manager import ConfigManager - print(" ✅ ConfigManager imported") - except Exception as e: - print(f" ❌ ConfigManager failed: {e}") - traceback.print_exc() - return False - - print("\n2. Testing web interface imports...") - try: - from web_interface.app import app - print(" ✅ web_interface.app imported") - print(f" 📋 App object: {app}") - except Exception as e: - print(f" ❌ web_interface.app failed: {e}") - traceback.print_exc() - return False - - print("\n3. Checking config...") - try: - config_manager = ConfigManager() - config = config_manager.load_config() - print(" ✅ Config loaded") - - # Same rule ledmatrix-web.service applies: only an explicit false/off - # keeps the web interface down; a missing key means on. - sys.path.insert(0, str(project_root / 'scripts' / 'utils')) - from start_web_conditionally import autostart_enabled - raw = config.get('web_display_autostart', '(not set, defaults to on)') - state = 'starts' if autostart_enabled(config) else 'will NOT start' - print(f" 🔧 web_display_autostart: {raw} (web interface {state})") - except Exception as e: - print(f" ❌ Config check failed: {e}") - traceback.print_exc() - return False - - print("\n4. Testing Flask startup...") - try: - print(" 🚀 Starting Flask app...") - print(" 📍 Will run on: http://0.0.0.0:5000") - print(" ⏹️ Press Ctrl+C to stop") - - # Run the app (debug mode controlled by env var to satisfy security scanners) - _debug = os.environ.get('LEDMATRIX_FLASK_DEBUG', '0') == '1' - app.run(host='0.0.0.0', port=5000, debug=_debug) - - except KeyboardInterrupt: - print("\n ⏹️ Server stopped by user") - return True - except Exception as e: - print(f" ❌ Flask startup failed: {e}") - traceback.print_exc() - return False - -if __name__ == "__main__": - try: - success = main() - if success: - print("\n✅ Debug completed successfully") - else: - print("\n❌ Debug found issues - check output above") - except Exception as e: - print(f"\n💥 Debug script crashed: {e}") - traceback.print_exc() diff --git a/scripts/dev/README.md b/scripts/dev/README.md index cec5a631..01b1ebc9 100644 --- a/scripts/dev/README.md +++ b/scripts/dev/README.md @@ -6,7 +6,6 @@ This directory contains scripts and utilities for development and testing. - **`dev_plugin_setup.sh`** - Sets up plugin development environment by linking plugin repositories - **`run_emulator.sh`** - Runs the LED Matrix display in emulator mode (for development without hardware) -- **`validate_python.py`** - Validates Python files for common formatting and syntax errors ## Usage @@ -30,8 +29,3 @@ links. To use a fork or another clone location, copy ./scripts/dev/run_emulator.sh ``` -### Validating Python Files -```bash -python3 scripts/dev/validate_python.py -``` - diff --git a/scripts/dev/validate_python.py b/scripts/dev/validate_python.py deleted file mode 100644 index b10a3ee9..00000000 --- a/scripts/dev/validate_python.py +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env python3 -""" -Python file validation script to prevent common formatting errors. - -This script checks for: -1. Proper indentation (4 spaces, no mixed tabs/spaces) -2. Missing imports -3. Syntax errors -4. Line length issues -5. Proper try/except structure - -Usage: python tools/validate_python.py -""" - -import ast -import sys -import os - -def validate_file(filepath: str) -> bool: - """Validate a Python file for common issues.""" - try: - with open(filepath, 'r', encoding='utf-8') as f: - content = f.read() - - issues_found = [] - - # Check for tabs (should use spaces) - if '\t' in content: - issues_found.append("❌ Contains tabs - use 4 spaces instead") - - # Check for trailing whitespace - lines = content.split('\n') - for i, line in enumerate(lines, 1): - if line.rstrip() != line: - issues_found.append(f"❌ Line {i}: Trailing whitespace") - - # Check for very long lines - for i, line in enumerate(lines, 1): - if len(line) > 120: - issues_found.append(f"⚠️ Line {i}: Very long line ({len(line)} chars)") - - # Check for proper try/except structure - try: - ast.parse(content) - except SyntaxError as e: - issues_found.append(f"❌ Syntax error: {e}") - - # Check for mixed quotes (inconsistency) - single_quotes = content.count("'") - double_quotes = content.count('"') - if single_quotes > 0 and double_quotes > 0: - issues_found.append("⚠️ Mixed quote usage - consider using double quotes consistently") - - # Report results - if issues_found: - print(f"\n🔍 Validation Results for: {filepath}") - print("=" * 50) - for issue in issues_found: - print(issue) - return False - else: - print(f"✅ {filepath} - All checks passed!") - return True - - except Exception as e: - print(f"❌ Error reading file {filepath}: {e}") - return False - -def validate_directory(directory: str) -> bool: - """Validate all Python files in a directory.""" - all_passed = True - - for root, dirs, files in os.walk(directory): - for file in files: - if file.endswith('.py'): - filepath = os.path.join(root, file) - if not validate_file(filepath): - all_passed = False - - return all_passed - -if __name__ == "__main__": - if len(sys.argv) != 2: - print("Usage: python tools/validate_python.py ") - sys.exit(1) - - target = sys.argv[1] - - if os.path.isfile(target): - validate_file(target) - elif os.path.isdir(target): - validate_directory(target) - else: - print(f"❌ Path not found: {target}") - sys.exit(1) diff --git a/scripts/diagnose_plugin_permissions.sh b/scripts/diagnose_plugin_permissions.sh deleted file mode 100755 index 3e3b3104..00000000 --- a/scripts/diagnose_plugin_permissions.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/bin/bash -# Diagnostic script for plugin directory permissions -# Run this on the Raspberry Pi to check and fix plugin directory permissions - -set -e - -echo "==========================================" -echo "Plugin Directory Permissions Diagnostic" -echo "==========================================" -echo "" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Get the actual user -if [ -n "$SUDO_USER" ]; then - ACTUAL_USER="$SUDO_USER" -else - ACTUAL_USER=$(whoami) -fi - -# Get project root (parent of scripts/ directory) -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -PROJECT_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -PLUGINS_DIR="$PROJECT_ROOT_DIR/plugins" -PLUGIN_REPOS_DIR="$PROJECT_ROOT_DIR/plugin-repos" - -echo "Project root: $PROJECT_ROOT_DIR" -echo "User: $ACTUAL_USER" -echo "Running as: $(whoami)" -echo "" - -# Check parent directory permissions -echo "=== Parent Directory Permissions ===" -echo "Checking /home/$ACTUAL_USER:" -if [ -d "/home/$ACTUAL_USER" ]; then - PERMS=$(stat -c "%a %U:%G" "/home/$ACTUAL_USER") - echo " Permissions: $PERMS" - if [ "$(stat -c "%a" "/home/$ACTUAL_USER")" != "755" ] && [ "$(stat -c "%a" "/home/$ACTUAL_USER")" != "750" ]; then - echo -e " ${YELLOW}⚠ Warning: Home directory has restrictive permissions${NC}" - echo " Root may not be able to access subdirectories" - fi -else - echo -e " ${RED}✗ Home directory not found${NC}" -fi -echo "" - -echo "Checking $PROJECT_ROOT_DIR:" -if [ -d "$PROJECT_ROOT_DIR" ]; then - PERMS=$(stat -c "%a %U:%G" "$PROJECT_ROOT_DIR") - echo " Permissions: $PERMS" - if [ "$(stat -c "%a" "$PROJECT_ROOT_DIR")" != "755" ] && [ "$(stat -c "%a" "$PROJECT_ROOT_DIR")" != "750" ]; then - echo -e " ${YELLOW}⚠ Warning: Project directory has restrictive permissions${NC}" - fi -else - echo -e " ${RED}✗ Project directory not found${NC}" -fi -echo "" - -# Check plugins directory -echo "=== Plugins Directory ===" -if [ -d "$PLUGINS_DIR" ]; then - PERMS=$(stat -c "%a %U:%G" "$PLUGINS_DIR") - echo " Path: $PLUGINS_DIR" - echo " Permissions: $PERMS" - - OWNER=$(stat -c "%U" "$PLUGINS_DIR") - GROUP=$(stat -c "%G" "$PLUGINS_DIR") - PERM_BITS=$(stat -c "%a" "$PLUGINS_DIR") - - if [ "$OWNER" = "root" ] && [ "$GROUP" = "$ACTUAL_USER" ] && [ "$PERM_BITS" = "775" ]; then - echo -e " ${GREEN}✓ Correct permissions${NC}" - else - echo -e " ${RED}✗ Incorrect permissions${NC}" - echo " Expected: root:$ACTUAL_USER 775" - echo " Actual: $OWNER:$GROUP $PERM_BITS" - fi - - # Check if root can access - if sudo -u root test -r "$PLUGINS_DIR" && sudo -u root test -w "$PLUGINS_DIR"; then - echo -e " ${GREEN}✓ Root can read/write${NC}" - else - echo -e " ${RED}✗ Root cannot access${NC}" - fi -else - echo -e " ${YELLOW}⚠ Directory does not exist${NC}" -fi -echo "" - -# Check plugin-repos directory -echo "=== Plugin-Repos Directory ===" -if [ -d "$PLUGIN_REPOS_DIR" ]; then - PERMS=$(stat -c "%a %U:%G" "$PLUGIN_REPOS_DIR") - echo " Path: $PLUGIN_REPOS_DIR" - echo " Permissions: $PERMS" - - OWNER=$(stat -c "%U" "$PLUGIN_REPOS_DIR") - GROUP=$(stat -c "%G" "$PLUGIN_REPOS_DIR") - PERM_BITS=$(stat -c "%a" "$PLUGIN_REPOS_DIR") - - if [ "$OWNER" = "root" ] && [ "$GROUP" = "$ACTUAL_USER" ] && [ "$PERM_BITS" = "775" ]; then - echo -e " ${GREEN}✓ Correct permissions${NC}" - else - echo -e " ${RED}✗ Incorrect permissions${NC}" - echo " Expected: root:$ACTUAL_USER 775" - echo " Actual: $OWNER:$GROUP $PERM_BITS" - fi - - # Check if root can access - if sudo -u root test -r "$PLUGIN_REPOS_DIR" && sudo -u root test -w "$PLUGIN_REPOS_DIR"; then - echo -e " ${GREEN}✓ Root can read/write${NC}" - else - echo -e " ${RED}✗ Root cannot access${NC}" - fi - - # Try to list contents as root - echo " Testing root access:" - if sudo -u root ls "$PLUGIN_REPOS_DIR" >/dev/null 2>&1; then - echo -e " ${GREEN}✓ Root can list directory${NC}" - else - echo -e " ${RED}✗ Root cannot list directory${NC}" - echo " Error: $(sudo -u root ls "$PLUGIN_REPOS_DIR" 2>&1 | head -1)" - fi -else - echo -e " ${YELLOW}⚠ Directory does not exist${NC}" -fi -echo "" - -# Test if root can create files -echo "=== Testing Root Write Access ===" -TEST_FILE="$PLUGIN_REPOS_DIR/.permission_test_$$" -if sudo -u root touch "$TEST_FILE" 2>/dev/null; then - echo -e " ${GREEN}✓ Root can create files${NC}" - sudo -u root rm -f "$TEST_FILE" -else - echo -e " ${RED}✗ Root cannot create files${NC}" - echo " Error: $(sudo -u root touch "$TEST_FILE" 2>&1)" -fi -echo "" - -# Summary and fix recommendations -echo "=== Summary ===" -NEEDS_FIX=false - -if [ ! -d "$PLUGIN_REPOS_DIR" ]; then - echo -e "${YELLOW}⚠ plugin-repos directory does not exist${NC}" - NEEDS_FIX=true -elif [ "$(stat -c "%U:%G" "$PLUGIN_REPOS_DIR" 2>/dev/null)" != "root:$ACTUAL_USER" ] || [ "$(stat -c "%a" "$PLUGIN_REPOS_DIR" 2>/dev/null)" != "775" ]; then - echo -e "${RED}✗ plugin-repos has incorrect permissions${NC}" - NEEDS_FIX=true -fi - -if [ "$NEEDS_FIX" = true ]; then - echo "" - echo "=== Fix Commands ===" - echo "Run these commands to fix permissions:" - echo "" - echo "sudo mkdir -p $PLUGIN_REPOS_DIR" - echo "sudo chown root:$ACTUAL_USER $PLUGIN_REPOS_DIR" - echo "sudo chmod 775 $PLUGIN_REPOS_DIR" - echo "" - echo "Or run the fix script:" - echo "sudo bash $PROJECT_ROOT_DIR/scripts/fix_perms/fix_plugin_permissions.sh" -else - echo -e "${GREEN}✓ All permissions look correct${NC}" -fi -echo "" - diff --git a/scripts/diagnose_web_ui.sh b/scripts/diagnose_web_ui.sh deleted file mode 100755 index 1bc26306..00000000 --- a/scripts/diagnose_web_ui.sh +++ /dev/null @@ -1,232 +0,0 @@ -#!/bin/bash -# LEDMatrix Web UI Diagnostic Script -# Run this on your Raspberry Pi to diagnose web UI startup issues - -set -e - -echo "==========================================" -echo "LEDMatrix Web UI Diagnostic Report" -echo "==========================================" -echo "" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Check if running as root or with sudo -if [ "$EUID" -ne 0 ]; then - echo -e "${YELLOW}Warning: Some checks require sudo. Running what we can...${NC}" -fi - -PROJECT_DIR="${HOME}/LEDMatrix" - -# Report web_display_autostart the way scripts/utils/start_web_conditionally.py -# (what ledmatrix-web.service runs) decides it: only an explicit false/off keeps -# the web interface down; a missing key or an unreadable config starts it. -# Prints "on ", "off ", "default" (key not set) or "unreadable". -web_autostart_state() { - (cd "$1" && python3 - 2>/dev/null <<'PY' -import json, os, sys -sys.path.insert(0, os.path.join(os.getcwd(), "scripts", "utils")) -try: - from start_web_conditionally import autostart_enabled -except Exception: - def autostart_enabled(config): - value = config.get("web_display_autostart", True) - if isinstance(value, str): - return value.strip().lower() not in ("off", "false", "no", "0") - return bool(value) -try: - with open(os.path.join("config", "config.json"), encoding="utf-8") as f: - config = json.load(f) -except Exception: - config = None -if not isinstance(config, dict): - print("unreadable") -elif "web_display_autostart" not in config: - print("default") -else: - raw = json.dumps(config["web_display_autostart"]) - print(("on " if autostart_enabled(config) else "off ") + raw) -PY - ) || echo "unknown" -} - -echo "1. Checking service status..." -echo "------------------------------" -if systemctl is-active --quiet ledmatrix-web 2>/dev/null || sudo systemctl is-active --quiet ledmatrix-web 2>/dev/null; then - echo -e "${GREEN}✓ Service is ACTIVE${NC}" - STATUS=$(sudo systemctl status ledmatrix-web --no-pager -l | head -n 3) - echo "$STATUS" -else - echo -e "${RED}✗ Service is NOT running${NC}" - sudo systemctl status ledmatrix-web --no-pager -l | head -n 10 || echo "Service may not be installed" -fi -echo "" - -echo "2. Checking if service is enabled..." -echo "------------------------------" -if systemctl is-enabled --quiet ledmatrix-web 2>/dev/null || sudo systemctl is-enabled --quiet ledmatrix-web 2>/dev/null; then - echo -e "${GREEN}✓ Service is enabled to start on boot${NC}" -else - echo -e "${YELLOW}⚠ Service is NOT enabled (won't start on boot)${NC}" -fi -echo "" - -echo "3. Checking configuration file..." -echo "------------------------------" -if [ -f "${PROJECT_DIR}/config/config.json" ]; then - echo -e "${GREEN}✓ Config file exists${NC}" - AUTOSTART=$(web_autostart_state "$PROJECT_DIR") - case "$AUTOSTART" in - on\ *) - echo -e "${GREEN}✓ web_display_autostart is ${AUTOSTART#on } (web UI starts)${NC}" - ;; - off\ *) - echo -e "${RED}✗ web_display_autostart is ${AUTOSTART#off } (web UI won't start!)${NC}" - echo " Fix: Edit config.json and set 'web_display_autostart': true" - ;; - default) - echo -e "${GREEN}✓ web_display_autostart is not set (defaults to on; web UI starts)${NC}" - ;; - unreadable) - echo -e "${YELLOW}⚠ config.json could not be parsed (the web UI still starts so it can be repaired)${NC}" - ;; - *) - echo -e "${YELLOW}⚠ Could not evaluate web_display_autostart (python3 unavailable?)${NC}" - ;; - esac -else - echo -e "${RED}✗ Config file NOT FOUND at ${PROJECT_DIR}/config/config.json${NC}" -fi -echo "" - -echo "4. Checking recent service logs..." -echo "------------------------------" -RECENT_LOGS=$(sudo journalctl -u ledmatrix-web -n 30 --no-pager 2>/dev/null || echo "No logs available") -if [ -n "$RECENT_LOGS" ] && [ "$RECENT_LOGS" != "No logs available" ]; then - echo "$RECENT_LOGS" - echo "" - echo "Key messages from logs:" - echo "$RECENT_LOGS" | grep -i "web_display_autostart\|Configuration\|Launching\|will not\|Failed\|Error\|Starting" || echo " (no key messages found)" -else - echo -e "${YELLOW}⚠ No recent logs found${NC}" -fi -echo "" - -echo "5. Checking web interface files..." -echo "------------------------------" -FILES_TO_CHECK=( - "scripts/utils/start_web_conditionally.py" - "web_interface/start.py" - "web_interface/app.py" - "web_interface/requirements.txt" - "web_interface/blueprints/api_v3/__init__.py" - "web_interface/blueprints/pages_v3.py" -) - -for file in "${FILES_TO_CHECK[@]}"; do - if [ -f "${PROJECT_DIR}/${file}" ]; then - echo -e "${GREEN}✓ ${file}${NC}" - else - echo -e "${RED}✗ ${file} MISSING${NC}" - fi -done -echo "" - -echo "6. Checking Python import test..." -echo "------------------------------" -cd "${PROJECT_DIR}" 2>/dev/null || { - echo -e "${RED}✗ Cannot access project directory: ${PROJECT_DIR}${NC}" - echo "" - exit 1 -} - -if python3 -c "from web_interface.app import app; print('OK')" 2>&1; then - echo -e "${GREEN}✓ Flask app imports successfully${NC}" -else - echo -e "${RED}✗ Flask app import FAILED${NC}" - echo " Error details:" - python3 -c "from web_interface.app import app; print('OK')" 2>&1 | head -n 10 -fi -echo "" - -echo "7. Checking port 5000 availability..." -echo "------------------------------" -if command -v lsof &> /dev/null; then - PORT_CHECK=$(sudo lsof -i :5000 2>/dev/null || echo "") - if [ -z "$PORT_CHECK" ]; then - echo -e "${GREEN}✓ Port 5000 is available${NC}" - else - echo -e "${YELLOW}⚠ Port 5000 is in use:${NC}" - echo "$PORT_CHECK" - fi -elif command -v ss &> /dev/null; then - PORT_CHECK=$(sudo ss -tlnp | grep :5000 || echo "") - if [ -z "$PORT_CHECK" ]; then - echo -e "${GREEN}✓ Port 5000 is available${NC}" - else - echo -e "${YELLOW}⚠ Port 5000 is in use:${NC}" - echo "$PORT_CHECK" - fi -else - echo -e "${YELLOW}⚠ Cannot check port (lsof/ss not available)${NC}" -fi -echo "" - -echo "8. Checking service file..." -echo "------------------------------" -if [ -f "/etc/systemd/system/ledmatrix-web.service" ]; then - echo -e "${GREEN}✓ Service file exists${NC}" - echo " Location: /etc/systemd/system/ledmatrix-web.service" - echo " WorkingDirectory: $(grep WorkingDirectory /etc/systemd/system/ledmatrix-web.service | cut -d'=' -f2 || echo 'not found')" - echo " ExecStart: $(grep ExecStart /etc/systemd/system/ledmatrix-web.service | cut -d'=' -f2 || echo 'not found')" -else - echo -e "${RED}✗ Service file NOT FOUND${NC}" - echo " Run: sudo ./install_web_service.sh (if available)" -fi -echo "" - -echo "9. Checking dependencies..." -echo "------------------------------" -if [ -f "${PROJECT_DIR}/web_interface/requirements.txt" ]; then - echo "Checking if Flask is installed..." - if python3 -c "import flask; print(f'Flask {flask.__version__}')" 2>/dev/null; then - echo -e "${GREEN}✓ Flask is installed${NC}" - else - echo -e "${RED}✗ Flask is NOT installed${NC}" - echo " Run: pip3 install --break-system-packages -r web_interface/requirements.txt" - fi -else - echo -e "${YELLOW}⚠ requirements.txt not found${NC}" -fi -echo "" - -echo "10. Manual startup test (dry run)..." -echo "------------------------------" -echo "To test manual startup, run:" -echo " cd ${PROJECT_DIR}" -echo " python3 web_interface/start.py" -echo "" - -echo "==========================================" -echo "Diagnostic Summary" -echo "==========================================" -echo "" -echo "Most common issues:" -echo " 1. web_display_autostart is set to false in config.json (a missing key means on)" -echo " 2. Service not enabled or not started" -echo " 3. Missing dependencies (Flask, etc.)" -echo " 4. Import errors in web_interface/app.py" -echo " 5. Port 5000 already in use" -echo "" -echo "Next steps:" -echo " - Review the checks above for any RED ✗ marks" -echo " - Check recent logs: sudo journalctl -u ledmatrix-web -n 50 --no-pager" -echo " - Follow logs in real-time: sudo journalctl -u ledmatrix-web -f" -echo " - Try manual start: cd ${PROJECT_DIR} && python3 web_interface/start.py" -echo "" -echo "==========================================" - diff --git a/scripts/download_nba_logos.py b/scripts/download_nba_logos.py deleted file mode 100644 index 99bb5b4b..00000000 --- a/scripts/download_nba_logos.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python3 -""" -Script to download all NBA team logos from ESPN API and save them in assets/sports/nba_logos/ -""" -import sys -import os -import logging -from typing import Tuple - -# Add the project root to Python path so we can import the logo downloader -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -# Set up logging -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s' -) -logger = logging.getLogger(__name__) - -def download_nba_logos(force_download: bool = False) -> Tuple[int, int]: - """ - Download all NBA team logos from ESPN API. - - Args: - force_download: Whether to re-download existing logos - - Returns: - Tuple of (downloaded_count, failed_count) - """ - try: - from src.logo_downloader import download_all_logos_for_league - - logger.info("🏀 Starting NBA logo download...") - logger.info(f"Target directory: assets/sports/nba_logos/") - logger.info(f"Force download: {force_download}") - - # Use the existing function to download all NBA logos - downloaded_count, failed_count = download_all_logos_for_league('nba', force_download) - - logger.info("✅ NBA logo download complete!") - logger.info(f"📊 Summary: {downloaded_count} downloaded, {failed_count} failed") - - if downloaded_count > 0: - logger.info("🎉 NBA logos are now ready for use in the leaderboard!") - else: - logger.info("ℹ️ All NBA logos were already present or download failed for all teams") - - return downloaded_count, failed_count - - except ImportError as e: - logger.error(f"❌ Import error: {e}") - logger.info("💡 Make sure you're running this from the LEDMatrix project directory") - return 0, 0 - except Exception as e: - logger.error(f"❌ Unexpected error: {e}") - return 0, 0 - -def main(): - """Main function with command line argument parsing.""" - import argparse - - parser = argparse.ArgumentParser(description='Download all NBA team logos from ESPN API') - parser.add_argument( - '--force', - action='store_true', - help='Force re-download of existing logos' - ) - parser.add_argument( - '--quiet', - action='store_true', - help='Reduce logging output' - ) - - args = parser.parse_args() - - # Set logging level based on quiet flag - if args.quiet: - logging.getLogger().setLevel(logging.WARNING) - - logger.info("🚀 NBA Logo Downloader") - logger.info("=" * 50) - - # Download the logos - downloaded, failed = download_nba_logos(args.force) - - # Exit with appropriate code - if failed > 0 and downloaded == 0: - logger.error("❌ All downloads failed!") - sys.exit(1) - elif failed > 0: - logger.warning(f"⚠️ {failed} downloads failed, but {downloaded} succeeded") - sys.exit(0) # Partial success is still success - else: - logger.info("🎉 All NBA logos downloaded successfully!") - sys.exit(0) - -if __name__ == "__main__": - main() diff --git a/scripts/fix_internet_connectivity.sh b/scripts/fix_internet_connectivity.sh deleted file mode 100755 index 6971c6ba..00000000 --- a/scripts/fix_internet_connectivity.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/bash -# Emergency script to fix internet connectivity issues -# Run this if the Pi can't access the internet after AP mode testing - -echo "==========================================" -echo "Internet Connectivity Fix Script" -echo "==========================================" -echo "" - -# 1. Disable IP forwarding -echo "1. Disabling IP forwarding..." -sudo sysctl -w net.ipv4.ip_forward=0 -echo " ✓ IP forwarding disabled" - -# 2. Stop and disable dnsmasq (if it's interfering) -echo "" -echo "2. Checking dnsmasq..." -if sudo systemctl is-active dnsmasq > /dev/null 2>&1; then - echo " ⚠ dnsmasq is running - stopping it..." - sudo systemctl stop dnsmasq - sudo systemctl disable dnsmasq - echo " ✓ dnsmasq stopped" -else - echo " ✓ dnsmasq is not running" -fi - -# 3. Restore dnsmasq config if backup exists -echo "" -echo "3. Checking dnsmasq config..." -if [ -f /etc/dnsmasq.conf.backup ]; then - echo " ⚠ Found backup config - restoring..." - sudo cp /etc/dnsmasq.conf.backup /etc/dnsmasq.conf - echo " ✓ Config restored" -else - echo " ✓ No backup config found (normal)" -fi - -# 4. Restart NetworkManager to restore DNS -echo "" -echo "4. Restarting NetworkManager..." -sudo systemctl restart NetworkManager -sleep 2 -echo " ✓ NetworkManager restarted" - -# 5. Check DNS resolution -echo "" -echo "5. Testing DNS resolution..." -if nslookup google.com > /dev/null 2>&1; then - echo " ✓ DNS resolution working" -else - echo " ✗ DNS resolution failed" - echo " → Try: sudo systemctl restart systemd-resolved" -fi - -# 6. Test internet connectivity -echo "" -echo "6. Testing internet connectivity..." -if ping -c 2 8.8.8.8 > /dev/null 2>&1; then - echo " ✓ Internet connectivity working" -else - echo " ✗ Internet connectivity failed" - echo " → Check: ip route show" - echo " → Check: ip addr show" -fi - -# 7. Check if AP mode is still active -echo "" -echo "7. Checking AP mode status..." -if sudo systemctl is-active hostapd > /dev/null 2>&1; then - echo " ⚠ AP mode is still active!" - echo " → To disable: cd ~/LEDMatrix && python3 -c 'from src.wifi_manager import WiFiManager; wm = WiFiManager(); wm.disable_ap_mode()'" -else - echo " ✓ AP mode is not active" -fi - -# 8. Remove any leftover iptables rules -echo "" -echo "8. Checking iptables rules..." -if command -v iptables > /dev/null 2>&1; then - # Try to remove any port 80 redirect rules - sudo iptables -t nat -D PREROUTING -i wlan0 -p tcp --dport 80 -j REDIRECT --to-port 5000 2>/dev/null - sudo iptables -D INPUT -i wlan0 -p tcp --dport 80 -j ACCEPT 2>/dev/null - echo " ✓ Cleaned up iptables rules (if any existed)" -else - echo " → iptables not available (normal on some systems)" -fi - -echo "" -echo "==========================================" -echo "Fix Complete" -echo "==========================================" -echo "" -echo "If internet still doesn't work:" -echo "1. Check: ip route show" -echo "2. Check: cat /etc/resolv.conf" -echo "3. Restart network: sudo systemctl restart NetworkManager" -echo "4. Check Ethernet connection: ip link show eth0" -echo "" - - - - - - - - - - - diff --git a/scripts/install/README.md b/scripts/install/README.md index dc092d9d..544ea336 100644 --- a/scripts/install/README.md +++ b/scripts/install/README.md @@ -19,9 +19,6 @@ This directory contains scripts for installing and configuring the LEDMatrix sys (the user who runs the script, i.e. the one you installed LEDMatrix as; there is no `ledmatrix` system user) the passwordless `nmcli` and related WiFi permissions the web interface needs -- **`migrate_config.sh`** - Migrates configuration files to new formats (if needed) -- **`debug_install.sh`** - Diagnostic helper used when an install - fails; collects environment info and recent logs ## Usage diff --git a/scripts/install/debug_install.sh b/scripts/install/debug_install.sh deleted file mode 100755 index 7f094217..00000000 --- a/scripts/install/debug_install.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -# Quick diagnostic script to check why first_time_install.sh is failing -# Run this on the Pi: bash debug_install.sh - -echo "=== Diagnostic Script for Installation Failure ===" -echo "" - -echo "1. Checking if running as root:" -if [ "$EUID" -eq 0 ]; then - echo " ✓ Running as root (EUID=$EUID)" -else - echo " ✗ NOT running as root (EUID=$EUID, user=$(whoami))" -fi -echo "" - -echo "2. Checking if first_time_install.sh exists:" -if [ -f "./first_time_install.sh" ]; then - echo " ✓ Found ./first_time_install.sh" - echo " Checking if executable:" - if [ -x "./first_time_install.sh" ]; then - echo " ✓ Is executable" - else - echo " ✗ NOT executable (fix with: chmod +x first_time_install.sh)" - fi -else - echo " ✗ NOT found in current directory" - echo " Current directory: $(pwd)" -fi -echo "" - -echo "3. Testing argument passing with -y flag:" -echo " Running: bash ./first_time_install.sh -y --help 2>&1 | head -20" -if [ -f "./first_time_install.sh" ]; then - bash ./first_time_install.sh -y --help 2>&1 | head -20 || echo " ✗ Script failed or not found" -else - echo " ✗ first_time_install.sh not found" -fi -echo "" - -echo "4. Checking environment variable:" -echo " LEDMATRIX_ASSUME_YES=${LEDMATRIX_ASSUME_YES:-not set}" -echo " Testing with env: env LEDMATRIX_ASSUME_YES=1 bash -c 'echo ASSUME_YES would be set'" -env LEDMATRIX_ASSUME_YES=1 bash -c 'echo " ASSUME_YES would be: ${LEDMATRIX_ASSUME_YES:-not set}"' -echo "" - -echo "5. Testing sudo with arguments:" -echo " Command: sudo -E env LEDMATRIX_ASSUME_YES=1 bash ./first_time_install.sh -y --help 2>&1 | head -20" -if [ -f "./first_time_install.sh" ]; then - sudo -E env LEDMATRIX_ASSUME_YES=1 bash ./first_time_install.sh -y --help 2>&1 | head -20 || echo " ✗ Sudo command failed" -else - echo " ✗ first_time_install.sh not found" -fi -echo "" - -echo "6. Checking /tmp permissions:" -echo " /tmp is writable: $([ -w /tmp ] && echo 'YES' || echo 'NO')" -echo " /tmp permissions: $(stat -c '%a' /tmp 2>/dev/null || echo 'unknown')" -echo " TMPDIR: ${TMPDIR:-not set}" -echo "" - -echo "7. Checking stdin/TTY:" -if [ -t 0 ]; then - echo " ✓ stdin is a TTY (interactive)" -else - echo " ✗ stdin is NOT a TTY (non-interactive/pipe)" - echo " This is expected when running via curl | bash" -fi -echo "" - -echo "8. Latest installation log:" -# Determine project root directory (parent of scripts/install/) -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -LOG_DIR="$PROJECT_ROOT_DIR/logs" -LOG_FILE=$(ls -t "$LOG_DIR"/first_time_install_*.log 2>/dev/null | head -1) -if [ -n "$LOG_FILE" ]; then - echo " Found: $LOG_FILE" - echo " Last 30 lines:" - tail -30 "$LOG_FILE" | sed 's/^/ /' -else - echo " No log files found in $LOG_DIR/" -fi -echo "" - -echo "=== Diagnostic Complete ===" diff --git a/scripts/install/migrate_config.sh b/scripts/install/migrate_config.sh deleted file mode 100755 index 0000bec4..00000000 --- a/scripts/install/migrate_config.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# LED Matrix Configuration Migration Script -# This script helps migrate existing config.json to the new template-based system - -set -e - -echo "==========================================" -echo "LED Matrix Configuration Migration Script" -echo "==========================================" -echo "" - -# Check if we're in the right directory -if [ ! -f "config/config.template.json" ]; then - echo "Error: config/config.template.json not found." - echo "Please run this script from the LEDMatrix project root directory." - exit 1 -fi - -# Check if config.json exists -if [ ! -f "config/config.json" ]; then - echo "No existing config.json found. Creating from template..." - cp config/config.template.json config/config.json - echo "✓ Created config/config.json from template" - echo "" - echo "You can now edit config/config.json with your preferences." - exit 0 -fi - -echo "Existing config.json found. The system will automatically handle migration." -echo "" -echo "What this means:" -echo "- Your current config.json will be preserved" -echo "- New configuration options will be automatically added with default values" -echo "- A backup will be created before any changes" -echo "- The system handles this automatically when it starts" -echo "" -echo "No manual migration is needed. The ConfigManager will handle everything automatically." -echo "" -echo "To see the latest configuration options, you can reference:" -echo " config/config.template.json" -echo "" -echo "Migration complete!" diff --git a/scripts/setup_plugin_repos.py b/scripts/setup_plugin_repos.py deleted file mode 100755 index 060637b9..00000000 --- a/scripts/setup_plugin_repos.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -""" -Setup plugin repository symlinks for local development. - -Creates symlinks in plugin-repos/ pointing to plugin directories -in the ledmatrix-plugins monorepo. -""" - -import json -import os -import re -import sys -from pathlib import Path - -PROJECT_ROOT = Path(__file__).parent.parent -PLUGIN_REPOS_DIR = PROJECT_ROOT / "plugin-repos" -MONOREPO_PLUGINS = PROJECT_ROOT.parent / "ledmatrix-plugins" / "plugins" - - -def parse_json_with_trailing_commas(text: str) -> dict: - """Parse JSON that may have trailing commas. - - Note: The regex also matches commas inside string values (e.g., "hello, }"). - This is fine for manifest files but may corrupt complex JSON with such patterns. - """ - text = re.sub(r",\s*([}\]])", r"\1", text) - return json.loads(text) - - -def create_symlinks() -> bool: - """Create symlinks in plugin-repos/ pointing to monorepo plugin dirs.""" - if not MONOREPO_PLUGINS.exists(): - print(f"Error: Monorepo plugins directory not found: {MONOREPO_PLUGINS}") - return False - - PLUGIN_REPOS_DIR.mkdir(exist_ok=True) - - created = 0 - skipped = 0 - - print("Setting up plugin symlinks...") - print(f" Source: {MONOREPO_PLUGINS}") - print(f" Links: {PLUGIN_REPOS_DIR}") - print() - - for plugin_dir in sorted(MONOREPO_PLUGINS.iterdir()): - if not plugin_dir.is_dir(): - continue - manifest_path = plugin_dir / "manifest.json" - if not manifest_path.exists(): - continue - - try: - with open(manifest_path, "r", encoding="utf-8") as f: - manifest = parse_json_with_trailing_commas(f.read()) - except (OSError, json.JSONDecodeError) as e: - print(f" {plugin_dir.name} - failed to read {manifest_path}: {e}") - continue - plugin_id = manifest.get("id", plugin_dir.name) - link_path = PLUGIN_REPOS_DIR / plugin_id - - if link_path.exists() or link_path.is_symlink(): - if link_path.is_symlink(): - try: - if link_path.resolve() == plugin_dir.resolve(): - skipped += 1 - continue - else: - link_path.unlink() - except OSError: - link_path.unlink() - else: - print(f" {plugin_id} - exists but is not a symlink, skipping") - skipped += 1 - continue - - relative_path = os.path.relpath(plugin_dir, link_path.parent) - link_path.symlink_to(relative_path) - print(f" {plugin_id} - linked") - created += 1 - - print(f"\nCreated {created} links, skipped {skipped}") - return True - - -def main(): - print("Setting up plugin repository symlinks from monorepo...\n") - if not create_symlinks(): - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/scripts/utils/README.md b/scripts/utils/README.md index 61bd2ac4..9339d65d 100644 --- a/scripts/utils/README.md +++ b/scripts/utils/README.md @@ -7,8 +7,6 @@ This directory contains utility scripts for maintenance and system operations. - **`clear_cache.py`** - Clears LEDMatrix cache data (specific keys or all cache) - **`start_web_conditionally.py`** - Conditionally starts the web interface based on config settings - **`wifi_monitor_daemon.py`** - Background daemon that monitors WiFi/Ethernet connection and manages access point mode -- **`cleanup_venv.sh`** - Cleans up Python virtual environment files -- **`clear_python_cache.sh`** - Clears Python cache files (__pycache__, *.pyc, etc.) - **`pixlet_config_editor.sh`** - Opens Pixlet's own config UI for one installed Starlark app - **`apply_dns_single_request.sh`** - Adds `options single-request` to the resolver (run by `ledmatrix-dns-fix.service`) diff --git a/scripts/utils/cleanup_venv.sh b/scripts/utils/cleanup_venv.sh deleted file mode 100755 index 887289c5..00000000 --- a/scripts/utils/cleanup_venv.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# Cleanup script to remove virtual environment if it exists -# This script removes the venv_web_v2 directory if it exists - -set -e - -# Get the directory where this script is located -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -cd "$SCRIPT_DIR" - -echo "Cleaning up virtual environment..." - -# Check if virtual environment exists and remove it -if [ -d "venv_web_v2" ]; then - echo "Removing existing virtual environment..." - rm -rf venv_web_v2 - echo "Virtual environment removed successfully" -else - echo "No virtual environment found to remove" -fi - -echo "Cleanup complete!" diff --git a/scripts/utils/clear_python_cache.sh b/scripts/utils/clear_python_cache.sh deleted file mode 100755 index 2b9eefba..00000000 --- a/scripts/utils/clear_python_cache.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Clear Python cache files that might be causing import issues - -echo "🧹 Clearing Python cache files..." - -# Clear __pycache__ directories -find ~/LEDMatrix -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true - -# Clear .pyc files -find ~/LEDMatrix -name "*.pyc" -delete 2>/dev/null || true - -# Clear Flask session cache if it exists -rm -rf ~/LEDMatrix/web_interface/.webassets-cache 2>/dev/null || true - -echo "✅ Python cache cleared" - -echo "" -echo "🔄 Now try running the web interface again:" -echo "cd ~/LEDMatrix" -echo "python3 web_interface/start.py" diff --git a/scripts/verify_web_ui.sh b/scripts/verify_web_ui.sh deleted file mode 100755 index 2dfc7628..00000000 --- a/scripts/verify_web_ui.sh +++ /dev/null @@ -1,164 +0,0 @@ -#!/bin/bash - -# Quick Web UI Verification Script -# Run this via SSH on your Raspberry Pi to verify the web interface is running - -echo "==========================================" -echo "Web UI Verification" -echo "==========================================" -echo "" - -# The web interface binds port 5000 (web_interface/start.py). -WEB_PORT=5000 -PORT_PATTERN=":${WEB_PORT}([^0-9]|$)" - -# Colors -GREEN='\033[0;32m' -RED='\033[0;31m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# 1. Check service status -echo "1. Checking service status..." -if systemctl is-active --quiet ledmatrix-web.service 2>/dev/null; then - echo -e "${GREEN}✓${NC} ledmatrix-web.service is running" - - # Get detailed status - echo "" - echo "Service details:" - systemctl status ledmatrix-web.service --no-pager -l | head -15 -else - echo -e "${RED}✗${NC} ledmatrix-web.service is NOT running" - echo "" - echo "To start the service:" - echo " sudo systemctl start ledmatrix-web.service" - echo "" -fi -echo "" - -# 2. Check if port $WEB_PORT is listening -echo "2. Checking if port $WEB_PORT is listening..." -if command -v ss >/dev/null 2>&1; then - if ss -tuln 2>/dev/null | grep -qE "$PORT_PATTERN"; then - echo -e "${GREEN}✓${NC} Port $WEB_PORT is listening" - echo "" - echo "Active connections on port $WEB_PORT:" - ss -tuln | grep -E "$PORT_PATTERN" - else - echo -e "${RED}✗${NC} Port $WEB_PORT is NOT listening" - fi -elif command -v netstat >/dev/null 2>&1; then - if netstat -tuln 2>/dev/null | grep -qE "$PORT_PATTERN"; then - echo -e "${GREEN}✓${NC} Port $WEB_PORT is listening" - echo "" - echo "Active connections on port $WEB_PORT:" - netstat -tuln | grep -E "$PORT_PATTERN" - else - echo -e "${RED}✗${NC} Port $WEB_PORT is NOT listening" - fi -else - echo -e "${YELLOW}⚠${NC} Cannot check port (ss/netstat not available)" -fi -echo "" - -# 3. Test HTTP connection -echo "3. Testing HTTP connection..." -if curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://localhost:$WEB_PORT > /dev/null 2>&1; then - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://localhost:$WEB_PORT 2>/dev/null) - if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "301" ]; then - echo -e "${GREEN}✓${NC} Web interface is responding (HTTP $HTTP_CODE)" - else - echo -e "${YELLOW}⚠${NC} Web interface responded with HTTP $HTTP_CODE" - fi -else - echo -e "${RED}✗${NC} Cannot connect to web interface on port $WEB_PORT" -fi -echo "" - -# 4. Get Pi's IP address -echo "4. Network information..." -IP_ADDRESSES=$(hostname -I 2>/dev/null | awk '{print $1}') -if [ -n "$IP_ADDRESSES" ]; then - echo "Pi IP address(es): $IP_ADDRESSES" - echo "" - echo "Access web interface at:" - for ip in $IP_ADDRESSES; do - echo " http://$ip:$WEB_PORT" - done -else - echo -e "${YELLOW}⚠${NC} Could not determine IP address" -fi -echo "" - -# 5. Check recent logs -echo "5. Recent service logs (last 10 lines)..." -echo "----------------------------------------" -journalctl -u ledmatrix-web.service -n 10 --no-pager 2>/dev/null || echo "Could not retrieve logs" -echo "" - -# 6. Check for errors in logs -echo "6. Checking for errors in logs..." -ERROR_COUNT=$(journalctl -u ledmatrix-web.service --since "5 minutes ago" --no-pager 2>/dev/null | grep -i "error\|exception\|failed\|traceback" | wc -l) -if [ "$ERROR_COUNT" -gt 0 ]; then - echo -e "${YELLOW}⚠${NC} Found $ERROR_COUNT error(s) in last 5 minutes" - echo "" - echo "Recent errors:" - journalctl -u ledmatrix-web.service --since "5 minutes ago" --no-pager 2>/dev/null | grep -i "error\|exception\|failed\|traceback" | tail -5 -else - echo -e "${GREEN}✓${NC} No errors in recent logs" -fi -echo "" - -# Summary -echo "==========================================" -echo "Summary" -echo "==========================================" - -SERVICE_RUNNING=false -PORT_LISTENING=false -HTTP_RESPONDING=false - -if systemctl is-active --quiet ledmatrix-web.service 2>/dev/null; then - SERVICE_RUNNING=true -fi - -if (ss -tuln 2>/dev/null | grep -qE "$PORT_PATTERN") || (netstat -tuln 2>/dev/null | grep -qE "$PORT_PATTERN"); then - PORT_LISTENING=true -fi - -if curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://localhost:$WEB_PORT > /dev/null 2>&1; then - HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 http://localhost:$WEB_PORT 2>/dev/null) - if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "302" ] || [ "$HTTP_CODE" = "301" ]; then - HTTP_RESPONDING=true - fi -fi - -if [ "$SERVICE_RUNNING" = true ] && [ "$PORT_LISTENING" = true ] && [ "$HTTP_RESPONDING" = true ]; then - echo -e "${GREEN}✓ Web UI is running correctly${NC}" - echo "" - echo "You can access it at:" - for ip in $IP_ADDRESSES; do - echo " http://$ip:$WEB_PORT" - done - exit 0 -elif [ "$SERVICE_RUNNING" = false ]; then - echo -e "${RED}✗ Web UI service is not running${NC}" - echo "" - echo "To start it:" - echo " sudo systemctl start ledmatrix-web.service" - echo " sudo systemctl enable ledmatrix-web.service # to start on boot" - exit 1 -elif [ "$PORT_LISTENING" = false ]; then - echo -e "${RED}✗ Service is running but port $WEB_PORT is not listening${NC}" - echo "" - echo "Check logs for errors:" - echo " sudo journalctl -u ledmatrix-web.service -f" - exit 1 -else - echo -e "${YELLOW}⚠ Web UI may have issues${NC}" - echo "" - echo "Check logs for details:" - echo " sudo journalctl -u ledmatrix-web.service -f" - exit 1 -fi -