- Use `mmpm ui --start/--stop/--status` instead of `mmpm ui --port --host` - MMPM v4 manages GUI via pm2, not direct execution - Update status command to check pm2 status and get URL from mmpm - Auto-install UI if not present when starting service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
329 lines
7.5 KiB
Bash
329 lines
7.5 KiB
Bash
#!/bin/sh
|
|
# MMPM - MagicMirror Package Manager controller
|
|
# Manages MMPM inside MagicMirror2 LXC container
|
|
# Copyright (C) 2024-2026 CyberMind.fr
|
|
|
|
CONFIG="mmpm"
|
|
LXC_NAME="magicmirror2"
|
|
MMPM_REPO="https://github.com/Bee-Mar/mmpm.git"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: mmpmctl <command> [options]
|
|
|
|
Commands:
|
|
install Install MMPM in MagicMirror2 container
|
|
update Update MMPM to latest version
|
|
status Show MMPM status
|
|
logs Show MMPM logs (use -f to follow)
|
|
shell Open shell in container (MMPM context)
|
|
service-run Internal: run MMPM GUI under procd
|
|
service-stop Stop MMPM GUI
|
|
|
|
Module Management (via MMPM):
|
|
search <query> Search for modules
|
|
list List installed modules
|
|
install <module> Install a module
|
|
remove <module> Remove a module
|
|
upgrade [module] Upgrade module(s)
|
|
|
|
Examples:
|
|
mmpmctl install
|
|
mmpmctl search weather
|
|
mmpmctl install MMM-WeatherChart
|
|
mmpmctl list
|
|
|
|
MMPM Web GUI: http://<router-ip>:7891
|
|
EOF
|
|
}
|
|
|
|
log_info() { echo "[INFO] $*"; }
|
|
log_warn() { echo "[WARN] $*" >&2; }
|
|
log_error() { echo "[ERROR] $*" >&2; }
|
|
|
|
uci_get() { uci -q get ${CONFIG}.$1; }
|
|
uci_set() { uci set ${CONFIG}.$1="$2" && uci commit ${CONFIG}; }
|
|
|
|
load_config() {
|
|
port="$(uci_get main.port || echo 7891)"
|
|
address="$(uci_get main.address || echo 0.0.0.0)"
|
|
enabled="$(uci_get main.enabled || echo 0)"
|
|
}
|
|
|
|
# Check if MagicMirror2 LXC is running
|
|
check_mm2_running() {
|
|
if ! lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"; then
|
|
log_error "MagicMirror2 container not running"
|
|
log_error "Start it first: /etc/init.d/magicmirror2 start"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# MMPM binary path inside container
|
|
MMPM_BIN="/usr/local/bin/mmpm"
|
|
# Node.js PATH inside container (for npm)
|
|
NODE_PATH="/opt/nodejs/node-v24.13.0/bin:/usr/local/bin:/usr/bin:/bin"
|
|
|
|
# Check if MMPM is installed in container
|
|
is_mmpm_installed() {
|
|
lxc-attach -n "$LXC_NAME" -- test -x "$MMPM_BIN"
|
|
}
|
|
|
|
# Run MMPM command with proper PATH (for npm access)
|
|
run_mmpm() {
|
|
lxc-attach -n "$LXC_NAME" -- sh -c "export PATH=$NODE_PATH:\$PATH && $MMPM_BIN $*"
|
|
}
|
|
|
|
# Install MMPM in container
|
|
cmd_install() {
|
|
check_mm2_running || return 1
|
|
|
|
if is_mmpm_installed; then
|
|
log_info "MMPM is already installed"
|
|
return 0
|
|
fi
|
|
|
|
log_info "Installing MMPM in MagicMirror2 container..."
|
|
|
|
# Install dependencies and MMPM via pip
|
|
lxc-attach -n "$LXC_NAME" -- sh -c '
|
|
# Update package lists
|
|
apt-get update 2>/dev/null || apk update 2>/dev/null || true
|
|
|
|
# Install Python and pip if not present
|
|
if ! command -v pip3 >/dev/null 2>&1; then
|
|
apt-get install -y python3 python3-pip python3-venv 2>/dev/null || \
|
|
apk add python3 py3-pip 2>/dev/null || true
|
|
fi
|
|
|
|
# Install MMPM via pip (--break-system-packages for Debian Trixie PEP 668)
|
|
pip3 install --upgrade --break-system-packages mmpm 2>/dev/null || \
|
|
pip3 install --upgrade mmpm 2>/dev/null || \
|
|
pip install --upgrade --break-system-packages mmpm 2>/dev/null || \
|
|
pip install --upgrade mmpm
|
|
|
|
# Initialize MMPM database
|
|
mmpm db --yes 2>/dev/null || true
|
|
' || {
|
|
log_error "Failed to install MMPM"
|
|
return 1
|
|
}
|
|
|
|
log_info "MMPM installed successfully"
|
|
log_info "Enable and start the GUI: /etc/init.d/mmpm enable && /etc/init.d/mmpm start"
|
|
}
|
|
|
|
# Update MMPM
|
|
cmd_update() {
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed. Run 'mmpmctl install' first"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Updating MMPM..."
|
|
lxc-attach -n "$LXC_NAME" -- pip3 install --upgrade --break-system-packages mmpm 2>/dev/null || \
|
|
lxc-attach -n "$LXC_NAME" -- pip3 install --upgrade mmpm || {
|
|
log_error "Failed to update MMPM"
|
|
return 1
|
|
}
|
|
|
|
log_info "MMPM updated successfully"
|
|
}
|
|
|
|
# Show status
|
|
cmd_status() {
|
|
load_config
|
|
|
|
echo "=== MMPM Status ==="
|
|
echo ""
|
|
|
|
if ! lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING"; then
|
|
echo "MagicMirror2 container: NOT RUNNING"
|
|
echo "MMPM: N/A (container not running)"
|
|
return
|
|
fi
|
|
|
|
echo "MagicMirror2 container: RUNNING"
|
|
|
|
if is_mmpm_installed; then
|
|
local version=$(run_mmpm version 2>/dev/null | head -1 || echo "unknown")
|
|
echo "MMPM installed: YES (v$version)"
|
|
else
|
|
echo "MMPM installed: NO"
|
|
echo ""
|
|
echo "Install with: mmpmctl install"
|
|
return
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== GUI Status ==="
|
|
|
|
# Check if GUI is running via pm2
|
|
local ui_status=$(run_mmpm ui --status 2>/dev/null | grep "mmpm.ui" | grep -c "online" || echo "0")
|
|
if [ "$ui_status" != "0" ]; then
|
|
local gui_url=$(run_mmpm ui --url 2>/dev/null | grep -oE 'http://[^[:space:]]+' || echo "")
|
|
echo "GUI Status: RUNNING (pm2)"
|
|
echo "GUI URL: $gui_url"
|
|
else
|
|
echo "GUI Status: NOT RUNNING"
|
|
echo "Start with: /etc/init.d/mmpm start"
|
|
fi
|
|
}
|
|
|
|
# Show logs
|
|
cmd_logs() {
|
|
if [ "$1" = "-f" ]; then
|
|
logread -f -e mmpm
|
|
else
|
|
logread -e mmpm | tail -100
|
|
fi
|
|
}
|
|
|
|
# Start MMPM GUI (via pm2)
|
|
cmd_service_run() {
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Starting MMPM GUI..."
|
|
|
|
# Check if UI is installed, if not install it
|
|
local ui_status=$(run_mmpm ui --status 2>/dev/null | grep -c "mmpm.ui" || echo "0")
|
|
if [ "$ui_status" = "0" ]; then
|
|
log_info "Installing MMPM UI..."
|
|
run_mmpm ui install --yes 2>/dev/null || true
|
|
fi
|
|
|
|
# Start MMPM GUI via pm2
|
|
run_mmpm ui --start
|
|
}
|
|
|
|
# Stop MMPM GUI
|
|
cmd_service_stop() {
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
return 0
|
|
fi
|
|
|
|
log_info "Stopping MMPM GUI..."
|
|
run_mmpm ui --stop 2>/dev/null || true
|
|
}
|
|
|
|
# Search modules
|
|
cmd_search() {
|
|
local query="$1"
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$query" ]; then
|
|
log_error "Search query required"
|
|
return 1
|
|
fi
|
|
|
|
run_mmpm search "$query"
|
|
}
|
|
|
|
# List installed modules
|
|
cmd_list() {
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
run_mmpm list --installed
|
|
}
|
|
|
|
# Install module via MMPM
|
|
cmd_module_install() {
|
|
local module="$1"
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$module" ]; then
|
|
log_error "Module name required"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Installing module: $module"
|
|
run_mmpm install "$module" --yes
|
|
}
|
|
|
|
# Remove module via MMPM
|
|
cmd_module_remove() {
|
|
local module="$1"
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$module" ]; then
|
|
log_error "Module name required"
|
|
return 1
|
|
fi
|
|
|
|
log_info "Removing module: $module"
|
|
run_mmpm remove "$module" --yes
|
|
}
|
|
|
|
# Upgrade modules
|
|
cmd_upgrade() {
|
|
local module="$1"
|
|
check_mm2_running || return 1
|
|
|
|
if ! is_mmpm_installed; then
|
|
log_error "MMPM not installed"
|
|
return 1
|
|
fi
|
|
|
|
if [ -n "$module" ]; then
|
|
log_info "Upgrading module: $module"
|
|
run_mmpm upgrade "$module" --yes
|
|
else
|
|
log_info "Upgrading all modules..."
|
|
run_mmpm upgrade --yes
|
|
fi
|
|
}
|
|
|
|
# Open shell in container
|
|
cmd_shell() {
|
|
check_mm2_running || return 1
|
|
lxc-attach -n "$LXC_NAME" -- /bin/sh
|
|
}
|
|
|
|
# Main entry point
|
|
case "${1:-}" in
|
|
install) shift; cmd_install "$@" ;;
|
|
update) shift; cmd_update "$@" ;;
|
|
status) shift; cmd_status "$@" ;;
|
|
logs) shift; cmd_logs "$@" ;;
|
|
shell) shift; cmd_shell "$@" ;;
|
|
service-run) shift; cmd_service_run "$@" ;;
|
|
service-stop) shift; cmd_service_stop "$@" ;;
|
|
search) shift; cmd_search "$@" ;;
|
|
list) shift; cmd_list "$@" ;;
|
|
install-module) shift; cmd_module_install "$@" ;;
|
|
remove) shift; cmd_module_remove "$@" ;;
|
|
upgrade) shift; cmd_upgrade "$@" ;;
|
|
help|--help|-h|'') usage ;;
|
|
*) echo "Unknown command: $1" >&2; usage >&2; exit 1 ;;
|
|
esac
|