This project started out of frustration, and quite frankly, there could have been a lot easier ways to go about it. But this is truly what I love about Linux, and it has always been the angle I come at it from: sideways, but practical.
For some background, I come from a time when community guides just like this one got me through some very tough times in Linux. Coming from highly obscure distributions like Yoper, building things for myself out of sheer necessity was a must. I hope someone finds this useful, and either builds off it or shares it with others who need it. If you are feeling friendly, please feel free to share this with the Reddit community. I no longer have an account there, but with all the fun little scripts popping up over there lately, I am sure some of you do. Ultimately, I just felt like the Lemmy Bazzite community needed some more content!
I am going to call it closed on my end because it is working just the way I need it to: you trigger the script, the lights turn off, and the system sleeps. Press the system power button, the system wakes, the OpenRGB profiles load automatically, and I am right back to gaming. Happy gaming, Bazzite dudes!
Yes me and my little ai buddy worked on this.
This guide provides a reliable solution for an issue in Bazzite where motherboard, RAM, and case RGB lights remain illuminated, flash, or cycle colors when the system enters sleep mode, and lighting profiles fail to revert back to your custom OpenRGB settings upon wake.
By implementing a user-space automation script, you eliminate the need to enable restrictive BIOS power-saving states (like ErP). This allows you to keep your USB ports powered overnight to charge controllers and peripherals while ensuring your room remains completely dark during system sleep.
Path Customization Note
Throughout this guide and within the script configuration variables, the directory path /home/gamer is used as the standard system baseline example. If your Bazzite configuration uses a different username, replace gamer with your actual system username across all directory paths, script entries, and terminal commands to ensure the automation executes correctly.
How It Works
When triggered from your Steam library, the script manages your system’s transition into and out of sleep mode by handling hardware lighting configurations in an automated sequence:
- Before Sleep: It automatically darkens all hardware lighting components via OpenRGB.
- During Sleep: It safely initiates the operating system’s suspend sequence while leaving USB power lines active for charging and peripheral wake signals.
- Upon Wake: It waits for the USB devices to stabilize, then automatically restores your default lighting profile in the background, ensuring the Steam Game Mode interface never experiences freezes or lag.
This script integrates into Steam Game Mode as a Non-Steam shortcut. It intercepts the sleep command to darken your hardware before allowing the system to suspend, preventing interface freezes and ensuring a clean foreground exit when the system wakes.
The Prerequisites
Before deploying either script version, your system must meet two initial setup requirements:
1. Install OpenRGB via Bazzite Portal
OpenRGB must be installed natively through the Bazzite Portal (or via the terminal command ujust install-openrgb).
Important: Do not install OpenRGB as a standard Flatpak from the Discover software center. Flatpaks are sandboxed and lack the low-level kernel hardware rules (
udev) needed to communicate with your RGB controllers. The Bazzite Portal installation correctly configures these hardware permissions inside the operating system.
2. Configure Your Lighting Profiles
Open the OpenRGB application on your desktop and save two distinct profiles with these exact, case-sensitive names:
off– A profile where all zones, devices, and components are set to black (turned off).on– Your standard, everyday operational gaming lighting profile.
The Core Concept: Why AppImage Extraction is More Reliable
If an AppImage is launched immediately before suspend, the interaction between FUSE mounting and the suspend process can occasionally prevent OpenRGB from starting cleanly. Extracting the AppImage avoids this dependency by executing the native AppRun binary directly.
To maximize execution reliability, both solutions utilize the AppImage extraction flag (--appimage-extract). Extracting the AppImage into a regular folder structure exposes the native executable named AppRun. The script launches this binary directly in user space, making suspend behavior significantly more reliable and ensuring a clean power transition.
Choose Your Strategy
Select the implementation path that best fits your system maintenance preferences.
Strategy 1: Manual Mode (No Auto Update)
- Who it is for: Users who prefer complete control over their filesystem and do not want automated scripts moving, changing, or interacting with application folders in the background.
- Maintenance Requirement: Whenever you update OpenRGB via the Bazzite Portal, you must manually open the terminal and re-run the extraction command to update your script’s execution folder.
#!/bin/bash
# --- Configuration Variables ---
OPENRGB="/home/gamer/AppImages/OpenRGB-extracted/AppRun"
CONFIG="/home/gamer/.config/OpenRGB"
LOG_FILE="$HOME/openrgb-sleep.log"
# 1. Log Rotation: Prevent the log file from growing infinitely
if [ -f "$LOG_FILE" ] && [ "$(wc -l < "$LOG_FILE")" -gt 500 ]; then
# Keep only the last 200 lines of history
echo "$(tail -n 200 "$LOG_FILE")" > "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S'): Log rotated to prevent file bloat." >> "$LOG_FILE"
fi
# 2. Fail-Fast Validation: Ensure OpenRGB is actually there before doing anything
if [ ! -x "$OPENRGB" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S'): CRITICAL ERROR - OpenRGB binary not found or not executable at: $OPENRGB" >> "$LOG_FILE"
exit 1
fi
# 3. Log the event and attempt to turn lights off using the correct "off" profile
echo "$(date '+%Y-%m-%d %H:%M:%S'): Initiating sleep sequence - Powersaving LEDs" >> "$LOG_FILE"
"$OPENRGB" --config "$CONFIG" --profile off 2>> "$LOG_FILE" || "$OPENRGB" --config "$CONFIG" -c 2>> "$LOG_FILE"
# 4. Wait 3 seconds for motherboard power lines to settle
sleep 3
# 5. The kernel scheduler suspends this process context during system sleep
systemctl suspend
# ========================================================
# SYSTEM RESUMES HERE IF THE USER SESSION SURVIVES
# ========================================================
# 6. Spawn a background loop to handle eventual hardware readiness on wake
(
echo "$(date '+%Y-%m-%d %H:%M:%S'): System awoken - starting hardware polling loop" >> "$LOG_FILE"
# Poll the USB bus up to 5 times.
for i in {1..5}; do
if "$OPENRGB" --config "$CONFIG" --profile on 2>> "$LOG_FILE"; then
echo "$(date '+%Y-%m-%d %H:%M:%S'): Success - Profile 'on' applied on attempt $i" >> "$LOG_FILE"
break
fi
echo "$(date '+%Y-%m-%d %H:%M:%S'): Attempt $i failed - USB bus unready. Retrying..." >> "$LOG_FILE"
sleep 1
done
) &
# 7. Exit the foreground process cleanly so Steam registers a normal exit
exit 0
Strategy 2: Automated Mode
- Who it is for: Users who want a hands-off, “set-and-forget” implementation.
- How it works: It uses a timestamp check (
-nt). If the Bazzite Portal updates the main AppImage file, the script automatically identifies it during the next sleep transition. It safely renames your old folder with a unique calendar timestamp backup path (ensuring zero file deletion) and extracts the fresh version completely in the background.
#!/bin/bash
# --- Configuration Variables ---
APPIMAGE="/home/gamer/AppImages/openrgb.appimage"
EXTRACTED_DIR="/home/gamer/AppImages/OpenRGB-extracted"
OPENRGB="$EXTRACTED_DIR/AppRun"
CONFIG="/home/gamer/.config/OpenRGB"
LOG_FILE="$HOME/openrgb-sleep.log"
# === Automated Extraction & Update Lifecycle (Non-Destructive) ===
# Triggers if the folder is missing, or if the Portal downloaded a newer AppImage container
if [ -f "$APPIMAGE" ] && { [ ! -f "$OPENRGB" ] || [ "$APPIMAGE" -nt "$OPENRGB" ]; }; then
echo "$(date '+%Y-%m-%d %H:%M:%S'): Sync Action - New OpenRGB update or initial run detected." >> "$LOG_FILE"
cd /home/gamer/AppImages
# Defensive Architecture: Archive the legacy directory with a unique timestamp instead of deleting
if [ -d "$EXTRACTED_DIR" ]; then
TIMESTAMP=$(date '+%Y%m%d_%H%M%S')
BACKUP_PATH="${EXTRACTED_DIR}_bak_${TIMESTAMP}"
echo "$(date '+%Y-%m-%d %H:%M:%S'): Archiving legacy directory to: $BACKUP_PATH" >> "$LOG_FILE"
mv "$EXTRACTED_DIR" "$BACKUP_PATH"
fi
# Extract the new container seamlessly inside user space
./openrgb.appimage --appimage-extract >> "$LOG_FILE" 2>&1
# Rename default extraction directory to match script execution paths
mv squashfs-root "$EXTRACTED_DIR"
chmod +x "$OPENRGB"
echo "$(date '+%Y-%m-%d %H:%M:%S'): Sync Action - Update complete. AppRun binary ready." >> "$LOG_FILE"
fi
# 1. Log Rotation: Prevent the log file from growing infinitely
if [ -f "$LOG_FILE" ] && [ "$(wc -l < "$LOG_FILE")" -gt 500 ]; then
# Keep only the last 200 lines of history
echo "$(tail -n 200 "$LOG_FILE")" > "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S'): Log rotated to prevent file bloat." >> "$LOG_FILE"
fi
# 2. Fail-Fast Validation: Ensure OpenRGB is actually there before doing anything
if [ ! -x "$OPENRGB" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S'): CRITICAL ERROR - OpenRGB binary not found or not executable at: $OPENRGB" >> "$LOG_FILE"
exit 1
fi
# 3. Log the event and attempt to turn lights off using the correct "off" profile
echo "$(date '+%Y-%m-%d %H:%M:%S'): Initiating sleep sequence - Powersaving LEDs" >> "$LOG_FILE"
"$OPENRGB" --config "$CONFIG" --profile off 2>> "$LOG_FILE" || "$OPENRGB" --config "$CONFIG" -c 2>> "$LOG_FILE"
# 4. Wait 3 seconds for motherboard power lines to settle
sleep 3
# 5. The kernel scheduler suspends this process context during system sleep
systemctl suspend
# ========================================================
# SYSTEM RESUMES HERE IF THE USER SESSION SURVIVES
# ========================================================
# 6. Spawn a background loop to handle eventual hardware readiness on wake
(
echo "$(date '+%Y-%m-%d %H:%M:%S'): System awoken - starting hardware polling loop" >> "$LOG_FILE"
# Poll the USB bus up to 5 times.
for i in {1..5}; do
if "$OPENRGB" --config "$CONFIG" --profile on 2>> "$LOG_FILE"; then
echo "$(date '+%Y-%m-%d %H:%M:%S'): Success - Profile 'on' applied on attempt $i" >> "$LOG_FILE"
break
fi
echo "$(date '+%Y-%m-%d %H:%M:%S'): Attempt $i failed - USB bus unready. Retrying..." >> "$LOG_FILE"
sleep 1
done
) &
# 7. Exit the foreground process cleanly so Steam registers a normal exit
exit 0
Step-by-Step Implementation
Step 1: Save the Script and Grant Permissions
- Open your terminal (Konsole).
- Create a new file named
openrgb-sleep.shin a persistent user-space folder (e.g.,/home/gamer/openrgb-sleep.sh). Remember to replacegamerwith your actual username if it differs. - Paste the complete code block of your chosen strategy into the file and save it.
- Mark the script as executable by running:
chmod +x /home/gamer/openrgb-sleep.sh
Step 2: Initial Extraction (Required for Strategy 1 Only)
If you chose Strategy 1 (Manual Mode), you must manually perform the initial extraction so the script has a target binary to run:
- In the terminal, navigate to your AppImages folder:
cd ~/AppImages - Run the extraction flag:
./openrgb.appimage --appimage-extract - Rename the output folder to match the script’s configuration path:
mv squashfs-root OpenRGB-extracted
(Note: If you chose Strategy 2, skip this step entirely. The script handles it automatically on the first run).
Step 3: Add to Steam Game Mode
To trigger this script directly from your Game Mode interface using a controller, add it as a Non-Steam shortcut:
- Switch to the Bazzite Desktop environment and open the Steam Desktop Client.
- Click Add a Game (bottom-left corner) -> Add a Non-Steam Game…
- Click Browse, navigate to your script’s folder location, select
openrgb-sleep.sh, and click Add Selected Programs. - Locate the script in your Steam Library list, right-click it, and select Properties.
- Change the name to a clean title, such as
Sleep System. - Return to Game Mode. The script will now be fully operational under the Non-Steam tab in your library.
Verification Logs
To monitor script operations, verify profile application success, or check automated backup folder paths, view the rolling history log at any time by opening the following local file: /home/gamer/openrgb-sleep.log (substituting gamer with your custom username if applicable).
Sorry added a edit to the script cause Lemmy markup isn’t very nice to me!

