Files
Kiwy-Signage/install.sh
Kiwy Player 3531760e16 Fix autostart for Wayland: use system-wide service instead of user service
- Replaced failing systemd user service with system-wide service
- System service more reliable on Wayland/Bookworm systems
- Service creates /etc/systemd/system/kiwy-player.service
- Runs as pi user with proper display environment variables
- Adds Restart=on-failure for robustness
- Keeps XDG and cron methods as additional fallback layers

This resolves autostart failures after recent system updates.
2026-01-17 20:58:39 +02:00

631 lines
20 KiB
Bash

#!/bin/bash
# Kivy Signage Player Installation Script
# Supports both online and offline installation
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$SCRIPT_DIR/repo"
WHEELS_DIR="$REPO_DIR/python-wheels"
SYSTEM_DIR="$REPO_DIR/system-packages"
DEB_DIR="$SYSTEM_DIR/debs"
# Function to detect Raspberry Pi
detect_raspberry_pi() {
if grep -qi "raspberry" /proc/cpuinfo 2>/dev/null || [ -f /boot/config.txt ]; then
return 0 # Is Raspberry Pi
else
return 1 # Not Raspberry Pi
fi
}
# Function to setup autostart workflow
setup_autostart() {
echo ""
echo "=========================================="
echo "Setting up Autostart Workflow"
echo "=========================================="
# Determine the actual user (if running with sudo)
ACTUAL_USER="${SUDO_USER:-$(whoami)}"
ACTUAL_HOME=$(eval echo ~"$ACTUAL_USER")
AUTOSTART_DIR="$ACTUAL_HOME/.config/autostart"
SYSTEMD_DIR="$ACTUAL_HOME/.config/systemd/user"
LXDE_AUTOSTART="$ACTUAL_HOME/.config/lxsession/LXDE-pi/autostart"
# Method 1: XDG Autostart (works with most desktop environments including Wayland)
echo "Creating XDG autostart entry..."
mkdir -p "$AUTOSTART_DIR"
cat > "$AUTOSTART_DIR/kivy-signage-player.desktop" << 'EOF'
[Desktop Entry]
Type=Application
Name=Kivy Signage Player
Comment=Digital Signage Player
Exec=bash -c "cd $SCRIPT_DIR && exec bash start.sh"
Icon=media-video-display
Categories=Utility;
NoDisplay=false
Terminal=true
StartupNotify=false
Hidden=false
X-GNOME-Autostart-enabled=true
X-GNOME-Autostart-delay=5
EOF
# Replace $SCRIPT_DIR with actual path in the file
sed -i "s|\$SCRIPT_DIR|$SCRIPT_DIR|g" "$AUTOSTART_DIR/kivy-signage-player.desktop"
chown "$ACTUAL_USER:$ACTUAL_USER" "$AUTOSTART_DIR/kivy-signage-player.desktop"
chmod 644 "$AUTOSTART_DIR/kivy-signage-player.desktop"
echo "✓ XDG autostart entry created for user: $ACTUAL_USER"
# Method 2: LXDE Autostart (for Raspberry Pi OS with LXDE)
if [ -f "$LXDE_AUTOSTART" ]; then
echo "Configuring LXDE autostart..."
if ! grep -q "kivy-signage-player" "$LXDE_AUTOSTART"; then
echo "" >> "$LXDE_AUTOSTART"
echo "# Kivy Signage Player autostart" >> "$LXDE_AUTOSTART"
echo "@bash -c 'cd $SCRIPT_DIR && bash start.sh'" >> "$LXDE_AUTOSTART"
chown "$ACTUAL_USER:$ACTUAL_USER" "$LXDE_AUTOSTART"
echo "✓ Added to LXDE autostart"
fi
fi
# Method 3: System-wide systemd service (most reliable for Wayland)
echo "Creating system-wide systemd service..."
sudo tee /etc/systemd/system/kiwy-player.service > /dev/null << EOF
[Unit]
Description=Kiwy Signage Player
After=multi-user.target graphical.target display-manager.service
[Service]
Type=simple
User=$ACTUAL_USER
Environment="DISPLAY=:0"
Environment="XAUTHORITY=$ACTUAL_HOME/.Xauthority"
WorkingDirectory=$SCRIPT_DIR
ExecStart=/bin/bash $SCRIPT_DIR/start.sh
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable kiwy-player.service
echo "✓ System-wide systemd service created and enabled"
# Method 4: Cron job for fallback (starts at reboot)
echo "Setting up cron fallback..."
# Create a wrapper script that waits for desktop to be ready
CRON_WRAPPER="$SCRIPT_DIR/.start-player-cron.sh"
cat > "$CRON_WRAPPER" << 'EOF'
#!/bin/bash
# Wait for desktop environment to be ready
sleep 15
# Start the player
cd "$SCRIPT_DIR" && bash start.sh
EOF
sed -i "s|\$SCRIPT_DIR|$SCRIPT_DIR|g" "$CRON_WRAPPER"
chmod +x "$CRON_WRAPPER"
# Add to crontab for the actual user
CRON_ENTRY="@reboot sleep 20 && $CRON_WRAPPER > /tmp/kivy-player-cron.log 2>&1"
if ! su - "$ACTUAL_USER" -c "crontab -l 2>/dev/null" | grep -q "kivy-signage-player"; then
su - "$ACTUAL_USER" -c "(crontab -l 2>/dev/null || true; echo '$CRON_ENTRY') | crontab -" 2>/dev/null || true
echo "✓ Cron fallback configured"
fi
echo ""
echo "Autostart configuration methods:"
echo " 1. ✓ XDG Autostart Entry (~/.config/autostart/)"
echo " 2. ✓ systemd User Service (most reliable)"
if [ -f "$LXDE_AUTOSTART" ]; then
echo " 3. ✓ LXDE Autostart"
fi
echo " 4. ✓ Cron Fallback (@reboot)"
echo ""
echo "Status check command:"
echo " systemctl --user status kivy-signage-player.service"
echo ""
}
# Function to disable power-saving mode on Raspberry Pi
setup_raspberry_pi_power_management() {
echo ""
echo "=========================================="
echo "Raspberry Pi Detected - Configuring Power Management"
echo "=========================================="
# Disable HDMI power-saving
echo "Disabling HDMI screen power-saving..."
if [ -f /boot/config.txt ]; then
# Check if hdmi_blanking is already configured
if grep -q "hdmi_blanking" /boot/config.txt; then
sudo sed -i 's/^hdmi_blanking=.*/hdmi_blanking=0/' /boot/config.txt
else
echo "hdmi_blanking=0" | sudo tee -a /boot/config.txt > /dev/null
fi
# Disable HDMI CEC (can interfere with power management)
if grep -q "hdmi_ignore_cec_init" /boot/config.txt; then
sudo sed -i 's/^hdmi_ignore_cec_init=.*/hdmi_ignore_cec_init=1/' /boot/config.txt
else
echo "hdmi_ignore_cec_init=1" | sudo tee -a /boot/config.txt > /dev/null
fi
# Force HDMI mode to always be on
if grep -q "hdmi_force_hotplug" /boot/config.txt; then
sudo sed -i 's/^hdmi_force_hotplug=.*/hdmi_force_hotplug=1/' /boot/config.txt
else
echo "hdmi_force_hotplug=1" | sudo tee -a /boot/config.txt > /dev/null
fi
# Disable HDMI sleep mode
if grep -q "hdmi_ignore_edid" /boot/config.txt; then
sudo sed -i 's/^hdmi_ignore_edid=.*/hdmi_ignore_edid=0xa5000080/' /boot/config.txt
else
echo "hdmi_ignore_edid=0xa5000080" | sudo tee -a /boot/config.txt > /dev/null
fi
echo "✓ HDMI configuration locked in /boot/config.txt"
echo " - HDMI blanking disabled"
echo " - HDMI CEC disabled"
echo " - HDMI hotplug forced"
echo " - HDMI sleep mode disabled"
fi
# Disable screensaver and screen blanking in X11
echo "Configuring display blanking settings..."
# Create/update display configuration in home directory
XORG_DIR="/etc/X11/xorg.conf.d"
if [ -d "$XORG_DIR" ]; then
# Create display power management configuration
sudo tee "$XORG_DIR/99-no-blanking.conf" > /dev/null << 'EOF'
Section "ServerFlags"
Option "BlankTime" "0"
Option "StandbyTime" "0"
Option "SuspendTime" "0"
Option "OffTime" "0"
EndSection
Section "InputClass"
Identifier "Disable DPMS"
MatchClass "DPMS"
Option "DPMS" "false"
EndSection
EOF
echo "✓ X11 display blanking disabled"
fi
# Disable CPU power scaling (keep at max performance)
echo "Configuring CPU power management..."
# Create systemd service to keep CPU at max frequency
sudo tee /etc/systemd/system/disable-cpu-powersave.service > /dev/null << 'EOF'
[Unit]
Description=Disable CPU Power Saving for Signage Player
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c 'for cpu in /sys/devices/system/cpu/cpu[0-9]*; do echo performance > "$cpu/cpufreq/scaling_governor" 2>/dev/null; done'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
# Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable disable-cpu-powersave.service
sudo systemctl start disable-cpu-powersave.service
echo "✓ CPU power saving disabled (performance mode enabled)"
# Disable sleep/suspend
echo "Disabling system sleep and suspend..."
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target 2>/dev/null || true
echo "✓ System sleep/suspend disabled"
# Disable screensaver via xset (if X11 is running)
if command -v xset &> /dev/null; then
# Create .xinitrc if it doesn't exist to disable screensaver
if [ ! -f ~/.xinitrc ]; then
cat >> ~/.xinitrc << 'EOF'
# Disable screen blanking and screensaver
xset s off
xset -dpms
xset s noblank
EOF
else
# Update existing .xinitrc if needed
if ! grep -q "xset s off" ~/.xinitrc; then
cat >> ~/.xinitrc << 'EOF'
# Disable screen blanking and screensaver
xset s off
xset -dpms
xset s noblank
EOF
fi
fi
echo "✓ X11 screensaver disabled in .xinitrc"
fi
# Create screen keep-alive wrapper script
echo "Creating screen keep-alive service..."
KEEPALIVE_SCRIPT="$SCRIPT_DIR/.keep-screen-alive.sh"
cat > "$KEEPALIVE_SCRIPT" << 'EOF'
#!/bin/bash
# Keep-screen-alive wrapper for player
# Prevents screen from locking/turning off while player is running
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Function to keep screen awake
keep_screen_awake() {
while true; do
# Move mouse slightly to prevent idle
if command -v xdotool &> /dev/null; then
xdotool mousemove_relative 1 1
xdotool mousemove_relative -1 -1
fi
# Disable DPMS and screensaver periodically
if command -v xset &> /dev/null; then
xset s reset
xset dpms force on
fi
sleep 30
done
}
# Function to inhibit systemd sleep (if available)
inhibit_sleep() {
if command -v systemd-inhibit &> /dev/null; then
# Run player under systemd inhibit to prevent sleep
systemd-inhibit --what=sleep --why="Signage player running" \
bash "$SCRIPT_DIR/start.sh"
return $?
fi
return 1
}
# Try systemd inhibit first (most reliable)
if inhibit_sleep; then
exit 0
fi
# Fallback: Start keep-alive in background
keep_screen_awake &
KEEPALIVE_PID=$!
# Start the player
cd "$SCRIPT_DIR"
bash start.sh
PLAYER_EXIT=$?
# Kill keep-alive when player exits
kill $KEEPALIVE_PID 2>/dev/null || true
exit $PLAYER_EXIT
EOF
chmod +x "$KEEPALIVE_SCRIPT"
echo "✓ Screen keep-alive service created"
# Create systemd service to keep HDMI powered on
echo "Creating HDMI power control service..."
sudo tee /etc/systemd/system/hdmi-poweron.service > /dev/null << 'EOF'
[Unit]
Description=Keep HDMI Display Powered On
After=multi-user.target display-manager.service
[Service]
Type=simple
ExecStart=/bin/bash -c 'while true; do /usr/bin/tvservice -p 2>/dev/null; sleep 30; done'
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable hdmi-poweron.service
sudo systemctl start hdmi-poweron.service
echo "✓ HDMI power control service enabled"
# Create aggressive display keep-alive script
echo "Creating aggressive display keep-alive script..."
DISPLAY_KEEPALIVE="$SCRIPT_DIR/.display-keepalive.sh"
cat > "$DISPLAY_KEEPALIVE" << 'EOF'
#!/bin/bash
# Aggressive display keep-alive for Raspberry Pi
# Supports both X11 and Wayland environments
DISPLAY_TIMEOUT=30
# Detect display server type
detect_display_server() {
if [ -n "$WAYLAND_DISPLAY" ]; then
echo "wayland"
elif [ -n "$DISPLAY" ]; then
echo "x11"
else
echo "unknown"
fi
}
DISPLAY_SERVER=$(detect_display_server)
while true; do
# Keep HDMI powered on (works for both X11 and Wayland)
if command -v tvservice &> /dev/null; then
/usr/bin/tvservice -p 2>/dev/null
fi
if [ "$DISPLAY_SERVER" = "wayland" ]; then
# Wayland-specific power management
# Method 1: Use wlr-randr for Wayland compositors (if available)
if command -v wlr-randr &> /dev/null; then
wlr-randr --output HDMI-A-1 --on 2>/dev/null || true
fi
# Method 2: Prevent idle using systemd-inhibit
if command -v systemd-inhibit &> /dev/null; then
# This is already running, but refresh the lock
systemctl --user restart plasma-ksmserver.service 2>/dev/null || true
fi
# Method 3: Use wlopm (Wayland output power management)
if command -v wlopm &> /dev/null; then
wlopm --on \* 2>/dev/null || true
fi
# Method 4: Simulate activity via input (works on Wayland)
if command -v ydotool &> /dev/null; then
ydotool mousemove -x 1 -y 1 2>/dev/null || true
ydotool mousemove -x -1 -y -1 2>/dev/null || true
fi
# Method 5: GNOME/KDE Wayland idle inhibit
if command -v gnome-session-inhibit &> /dev/null; then
# Already inhibited by running process
true
fi
else
# X11-specific power management (original code)
if command -v xset &> /dev/null; then
DISPLAY=:0 xset s off 2>/dev/null
DISPLAY=:0 xset -dpms 2>/dev/null
DISPLAY=:0 xset dpms force on 2>/dev/null
DISPLAY=:0 xset s reset 2>/dev/null
fi
# Move mouse to trigger activity
if command -v xdotool &> /dev/null; then
DISPLAY=:0 xdotool mousemove_relative 1 1 2>/dev/null
DISPLAY=:0 xdotool mousemove_relative -1 -1 2>/dev/null
fi
# Disable monitor power saving
if command -v xrandr &> /dev/null; then
DISPLAY=:0 xrandr --output HDMI-1 --power-profile performance 2>/dev/null || true
fi
fi
sleep $DISPLAY_TIMEOUT
done
EOF
chmod +x "$DISPLAY_KEEPALIVE"
echo "✓ Display keep-alive script created"
# Install Wayland tools if using Wayland
echo "Checking for Wayland and installing necessary tools..."
if [ -n "$WAYLAND_DISPLAY" ] || pgrep -x "wayfire\|sway\|weston\|mutter" > /dev/null; then
echo "Wayland detected - installing Wayland power management tools..."
# Install wlopm for Wayland output power management
if ! command -v wlopm &> /dev/null; then
echo "Installing wlopm..."
# wlopm might need to be compiled from source or installed via package manager
sudo apt-get install -y wlopm 2>/dev/null || echo "Note: wlopm not available in package manager"
fi
# Install wlr-randr for wlroots compositors
if ! command -v wlr-randr &> /dev/null; then
echo "Installing wlr-randr..."
sudo apt-get install -y wlr-randr 2>/dev/null || echo "Note: wlr-randr not available"
fi
# Install ydotool (Wayland's xdotool alternative)
if ! command -v ydotool &> /dev/null; then
echo "Installing ydotool..."
sudo apt-get install -y ydotool 2>/dev/null || echo "Note: ydotool not available"
fi
echo "✓ Wayland tools installation attempted"
else
echo "X11 detected - using xset/xdotool/xrandr tools"
fi
# Update systemd screen keep-alive service to use this script
sudo tee /etc/systemd/system/screen-keepalive.service > /dev/null << EOF
[Unit]
Description=Keep Screen Awake During Signage Player
After=display-manager.service
PartOf=graphical-session.target
[Service]
Type=simple
User=$ACTUAL_USER
ExecStart=/bin/bash $DISPLAY_KEEPALIVE
Restart=always
RestartSec=5
Environment="DISPLAY=:0"
Environment="XAUTHORITY=%h/.Xauthority"
[Install]
WantedBy=graphical-session.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable screen-keepalive.service
echo "✓ Aggressive screen keep-alive service enabled"
echo ""
echo "⚠️ Note: Some changes require a system reboot to take effect."
echo "Please rerun this script after rebooting if power management issues persist."
echo ""
}
# Check for offline mode
OFFLINE_MODE=false
if [ "$1" == "--offline" ] || [ "$1" == "-o" ]; then
OFFLINE_MODE=true
echo "=========================================="
echo "Offline Installation Mode"
echo "=========================================="
elif [ -d "$WHEELS_DIR" ] && [ "$(ls -A $WHEELS_DIR 2>/dev/null)" ]; then
echo "=========================================="
echo "Offline packages detected - Using repo folder"
echo "=========================================="
OFFLINE_MODE=true
else
echo "=========================================="
echo "Online Installation Mode"
echo "=========================================="
fi
echo ""
echo "Installing Kivy Signage Player dependencies..."
echo ""
# Install system dependencies
echo "Step 1: Installing system dependencies..."
echo "--------------------"
if [ "$OFFLINE_MODE" = true ] && [ -d "$DEB_DIR" ] && [ "$(ls -A $DEB_DIR/*.deb 2>/dev/null)" ]; then
# Offline: Install from local .deb files
echo "Installing from offline .deb packages..."
cd "$DEB_DIR"
# Install all .deb files with dependencies
sudo dpkg -i *.deb 2>/dev/null || true
# Fix any broken dependencies
sudo apt-get install -f -y || true
echo "System packages installed from offline repository"
else
# Online: Use apt-get
echo "Updating package lists..."
sudo apt update
echo "Installing system packages..."
# Read packages from file if available, otherwise use default list
if [ -f "$SYSTEM_DIR/apt-packages.txt" ]; then
PACKAGES=$(grep -v '^#' "$SYSTEM_DIR/apt-packages.txt" | grep -v '^$' | tr '\n' ' ')
sudo apt install -y $PACKAGES
else
# Default package list
sudo apt install -y python3-pip python3-setuptools python3-dev
sudo apt install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
sudo apt install -y libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev
sudo apt install -y zlib1g-dev ffmpeg libavcodec-extra
sudo apt install -y gstreamer1.0-plugins-base gstreamer1.0-plugins-good
fi
echo "System packages installed successfully"
fi
echo ""
# Install Python dependencies
echo "Step 2: Installing Python dependencies..."
echo "--------------------"
if [ "$OFFLINE_MODE" = true ] && [ -d "$WHEELS_DIR" ] && [ "$(ls -A $WHEELS_DIR/*.whl 2>/dev/null)" ]; then
# Offline: Install from local wheels
echo "Installing from offline Python wheels..."
echo "Wheel files found: $(ls -1 $WHEELS_DIR/*.whl 2>/dev/null | wc -l)"
if pip3 install --break-system-packages --no-index --find-links="$WHEELS_DIR" -r requirements.txt 2>&1 | tee /tmp/pip_install.log; then
echo "Python packages installed from offline repository"
else
echo "Warning: Offline installation failed (possibly due to Python version mismatch)"
echo "Falling back to online installation..."
pip3 install --break-system-packages -r requirements.txt
echo "Python packages installed from PyPI"
fi
else
# Online: Use pip from PyPI
echo "Installing from PyPI..."
pip3 install --break-system-packages -r requirements.txt
echo "Python packages installed successfully"
fi
echo ""
echo "=========================================="
echo "Installation completed successfully!"
echo "=========================================="
echo ""
# Setup autostart workflow
setup_autostart
# Check if running on Raspberry Pi and setup power management
if detect_raspberry_pi; then
setup_raspberry_pi_power_management
fi
# Optimize video playback for Raspberry Pi
if detect_raspberry_pi; then
echo ""
echo "=========================================="
echo "Optimizing for Video Playback"
echo "=========================================="
# Run video optimization script
if [ -f "$SCRIPT_DIR/.video-optimization.sh" ]; then
bash "$SCRIPT_DIR/.video-optimization.sh"
fi
fi
echo "To run the signage player:"
echo " cd src && python3 main.py"
echo ""
echo "Or use the run script:"
echo " bash run_player.sh"
echo ""
echo "Or start the watchdog (with auto-restart on crash):"
echo " bash start.sh"
echo ""
echo "Autostart has been configured. The player will start automatically when the desktop loads."
echo ""
# Check if config exists
if [ ! -d "$SCRIPT_DIR/config" ] || [ ! "$(ls -A $SCRIPT_DIR/config)" ]; then
echo "⚠️ Note: No configuration found."
echo "Please configure the player before running:"
echo " 1. Copy config/app_config.txt.example to config/app_config.txt"
echo " 2. Edit the configuration file with your server details"
echo ""
fi