OpenRGB lavender stack: colour script, user units, resume watcher
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
# rgb-lavender
|
||||||
|
|
||||||
|
Catppuccin Latte lavender (`#7287FD`) on every RGB controller in the cachyos-gaming desktop
|
||||||
|
(ASUS Z790 Hero build), driven by OpenRGB and kept that way across suspend/resume.
|
||||||
|
|
||||||
|
## Pieces
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `bin/rgb-lavender` | Applies the colour to every device, resolving them by name. Tunables at the top (`RGB_COLOR`, sizes, headers). |
|
||||||
|
| `bin/rgb-resume-watch` | Listens on the system bus for logind `PrepareForSleep(false)` and restarts the OpenRGB server, which re-runs `rgb-lavender`. |
|
||||||
|
| `systemd/openrgb-server.service` | `openrgb --server --noautoconnect` as a user service. |
|
||||||
|
| `systemd/rgb-lavender.service` | Oneshot, `PartOf=openrgb-server.service` → re-applies whenever the server (re)starts. |
|
||||||
|
| `systemd/rgb-resume-watch.service` | Runs the watcher. Pure user-level, no root sleep hook. |
|
||||||
|
|
||||||
|
## Why the resume watcher
|
||||||
|
|
||||||
|
Corsair Commander Core XT, Lighting Node Pro and the Aura headers run in *direct* mode, which only
|
||||||
|
lives in controller RAM. After s2ram the USB controllers re-enumerate and lose it: XT fans go dark,
|
||||||
|
the rest fall back to firmware defaults, and the ENE DRAM drops off I2C until re-detected. The
|
||||||
|
login-time oneshot never re-runs, so the watcher does it for you (~10 s after wake).
|
||||||
|
|
||||||
|
## Gotchas (learned the hard way)
|
||||||
|
|
||||||
|
- **Always write the whole device.** A zone-only direct write starves the other zones and they go dark.
|
||||||
|
- Lighting Node Pro channels default to 14 LEDs — size to 204; `--size` must travel with mode+colour.
|
||||||
|
- Aura addressable headers start at 0 LEDs; same rule. Commander Core XT auto-sizes.
|
||||||
|
- ENE DRAM is firmware-static and survives boots; Glorious Model O detection is flaky and is skipped if absent.
|
||||||
|
- The `recv_select failed receiving magic` spam in the server log is just the detection poll in `rgb-lavender`.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./install.sh
|
||||||
|
RGB_COLOR=ca9ee6 rgb-lavender # try another colour ad hoc
|
||||||
|
```
|
||||||
Executable
+64
@@ -0,0 +1,64 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Apply a single colour to every RGB controller in this machine (ASUS Z790 Hero build).
|
||||||
|
# See ~/Nextcloud/Notes/Linux_RGB_OpenRGB_Catppuccin.md for the MSI/Fedora sibling and the why.
|
||||||
|
#
|
||||||
|
# Tunables (env overrides):
|
||||||
|
# RGB_COLOR hex, no '#'. Default: Catppuccin Latte lavender.
|
||||||
|
# ASUS_SIZE LED count for each Aura Addressable header (Aura max 120; oversizing is harmless in direct).
|
||||||
|
# NODEPRO_SIZE LED count per Lighting Node Pro channel (max 204).
|
||||||
|
# ASUS_ZONES which addressable headers to size (space list). Empty headers are still written by the
|
||||||
|
# device-wide pass, sizing them just lengthens the buffer.
|
||||||
|
set -u
|
||||||
|
RGB_COLOR=${RGB_COLOR:-7287FD}
|
||||||
|
ASUS_SIZE=${ASUS_SIZE:-120}
|
||||||
|
ASUS_ZONES=${ASUS_ZONES:-"1 2 3 4"}
|
||||||
|
NODEPRO_SIZE=${NODEPRO_SIZE:-204}
|
||||||
|
SERVER=${SERVER:-127.0.0.1:6742}
|
||||||
|
|
||||||
|
o() { openrgb --client "$SERVER" "$@" 2>&1 | grep -viE '^(client|connected|network)|^$'; }
|
||||||
|
|
||||||
|
# Wait until the server has actually finished detection (it accepts connections early).
|
||||||
|
# Count DISTINCT device names — the client double-connects, so raw line counts are doubled
|
||||||
|
# and a half-detected list passes a numeric threshold. Require the controllers we care about.
|
||||||
|
REQUIRED=("ENE DRAM" "Corsair Commander Core XT" "Corsair Lighting Node Pro" "ASUS ROG MAXIMUS Z790 HERO")
|
||||||
|
for _ in $(seq 1 90); do
|
||||||
|
l=$(openrgb --client "$SERVER" --list-devices 2>/dev/null | grep -E '^[0-9]+: ')
|
||||||
|
ok=1; for r in "${REQUIRED[@]}"; do echo "$l" | grep -qF "$r" || ok=0; done
|
||||||
|
[ "$ok" = 1 ] && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
sleep 2 # let the last-detected device settle before writing
|
||||||
|
|
||||||
|
# Device indices are resolved by name so re-detection order changes don't matter.
|
||||||
|
# Client double-connects → every device is listed twice; take the lowest index per name.
|
||||||
|
list=$(openrgb --client "$SERVER" --list-devices 2>/dev/null | grep -E '^[0-9]+: ')
|
||||||
|
idx() { echo "$list" | grep -F "$1" | head -1 | cut -d: -f1; }
|
||||||
|
idxs() { echo "$list" | grep -F "$1" | cut -d: -f1 | sort -n | head -n "$2"; }
|
||||||
|
|
||||||
|
# ENE DRAM x2 — firmware static, persists across boots.
|
||||||
|
for d in $(idxs 'ENE DRAM' 2); do o --device "$d" --mode static --color "$RGB_COLOR"; done
|
||||||
|
|
||||||
|
# Corsair Commander Core XT — ports 1-4 = fans, auto-sized by the controller (34/34/34/16). Direct only.
|
||||||
|
# Always write the WHOLE device: a zone-only write starves the other ports and they go dark.
|
||||||
|
d=$(idx 'Corsair Commander Core XT'); [ -n "$d" ] && o --device "$d" --mode direct --color "$RGB_COLOR"
|
||||||
|
|
||||||
|
# Corsair Lighting Node Pro — ch1 = ARGB strip, ch2 = 3 top fans + rear fan via LED hub.
|
||||||
|
# Channels default to 14 LEDs, which lights nothing useful; size both to the 204 max (surplus falls off).
|
||||||
|
# --size must travel with mode+colour. Then a device-wide write so neither channel starves in direct.
|
||||||
|
d=$(idx 'Corsair Lighting Node Pro')
|
||||||
|
if [ -n "$d" ]; then
|
||||||
|
for z in 0 1; do o --device "$d" --zone "$z" --size "$NODEPRO_SIZE" --mode direct --color "$RGB_COLOR"; done
|
||||||
|
o --device "$d" --mode direct --color "$RGB_COLOR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ASUS Aura — addressable headers start at 0 LEDs; size them (must travel with mode+colour),
|
||||||
|
# then a device-wide write so the mainboard zone is covered too.
|
||||||
|
d=$(idx 'ASUS ROG MAXIMUS Z790 HERO')
|
||||||
|
if [ -n "$d" ]; then
|
||||||
|
for z in $ASUS_ZONES; do o --device "$d" --zone "$z" --size "$ASUS_SIZE" --mode direct --color "$RGB_COLOR"; done
|
||||||
|
o --device "$d" --mode direct --color "$RGB_COLOR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Glorious Model O — stored in mouse firmware. Detection is flaky; skip silently if absent.
|
||||||
|
d=$(idx 'Glorious Model O'); [ -n "$d" ] && o --device "$d" --mode custom --color "$RGB_COLOR"
|
||||||
|
exit 0
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Re-apply RGB after suspend/resume. Direct-mode Corsair/Aura state is volatile and the USB
|
||||||
|
# controllers re-enumerate on wake, so restart the OpenRGB server (rgb-lavender.service is
|
||||||
|
# PartOf it and re-runs automatically). Pure user-level: watches logind's PrepareForSleep.
|
||||||
|
set -u
|
||||||
|
exec dbus-monitor --system "type='signal',interface='org.freedesktop.login1.Manager',member='PrepareForSleep'" |
|
||||||
|
while read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
*"boolean false"*)
|
||||||
|
sleep 3 # let USB finish re-enumerating before re-detecting
|
||||||
|
systemctl --user restart openrgb-server.service
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Install scripts + user units and start the stack.
|
||||||
|
set -eu
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
install -Dm755 bin/rgb-lavender bin/rgb-resume-watch -t ~/.local/bin
|
||||||
|
install -Dm644 systemd/*.service -t ~/.config/systemd/user
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user enable --now openrgb-server.service rgb-resume-watch.service
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=OpenRGB SDK server
|
||||||
|
After=graphical-session.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/openrgb --server --noautoconnect
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=3
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Apply Catppuccin lavender to all RGB devices
|
||||||
|
Requires=openrgb-server.service
|
||||||
|
After=openrgb-server.service
|
||||||
|
PartOf=openrgb-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=%h/.local/bin/rgb-lavender
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=openrgb-server.service
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Re-apply RGB colour after resume from suspend
|
||||||
|
After=openrgb-server.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=%h/.local/bin/rgb-resume-watch
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
Reference in New Issue
Block a user