fix: use openrgb static mode + SDK client to stop crashes on login
direct-mode color apply aborts (vector OOB → SIGABRT) on ASUS Aura devices that expose addressable zones with zero LEDs; switch to static mode, which applies the same color across all devices/zones without hitting that path. Also connect to the running OpenRGB SDK server via --client host:port instead of re-detecting all hardware on every toggle. This wires up the previously-unused openrgb.host/port config fields and removes a full USB/HID re-scan per command — that re-scan racing the server is what made it flakiest at login/boot. The existing retry logic now serves its intended purpose (waiting for the server to come up if the daemon starts first) rather than re-running a guaranteed-crashing command. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,9 @@ package openrgb
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -12,24 +14,30 @@ const (
|
||||
retryDelay = 3 * time.Second
|
||||
)
|
||||
|
||||
// Client controls RGB devices via the openrgb CLI.
|
||||
// Client controls RGB devices via the openrgb CLI. It talks to a running
|
||||
// OpenRGB SDK server (the --startminimized --server instance) rather than
|
||||
// re-detecting hardware on every command — local re-detection races with the
|
||||
// server for the USB/HID devices during login/boot and is unreliable.
|
||||
type Client struct {
|
||||
bin string
|
||||
bin string
|
||||
server string // host:port of the OpenRGB SDK server
|
||||
}
|
||||
|
||||
func Connect() (*Client, error) {
|
||||
func Connect(host string, port int) (*Client, error) {
|
||||
bin, err := exec.LookPath("openrgb")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("openrgb not found in PATH: %w", err)
|
||||
}
|
||||
|
||||
// Verify openrgb can list devices (confirms it's running/accessible)
|
||||
cmd := exec.Command(bin, "--list-devices")
|
||||
server := net.JoinHostPort(host, strconv.Itoa(port))
|
||||
|
||||
// Verify the SDK server is reachable (confirms it's up and enumerated).
|
||||
cmd := exec.Command(bin, "--client", server, "--list-devices")
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
return nil, fmt.Errorf("openrgb list-devices failed: %w\n%s", err, out)
|
||||
return nil, fmt.Errorf("openrgb client connect to %s failed: %w\n%s", server, err, out)
|
||||
}
|
||||
|
||||
return &Client{bin: bin}, nil
|
||||
return &Client{bin: bin, server: server}, nil
|
||||
}
|
||||
|
||||
func (c *Client) Close() error {
|
||||
@@ -39,9 +47,10 @@ func (c *Client) Close() error {
|
||||
// run executes an openrgb command with retries to handle transient failures
|
||||
// during early boot when device enumeration may not be complete.
|
||||
func (c *Client) run(args ...string) error {
|
||||
full := append([]string{"--client", c.server}, args...)
|
||||
var lastErr error
|
||||
for attempt := range maxRetries {
|
||||
cmd := exec.Command(c.bin, args...)
|
||||
cmd := exec.Command(c.bin, full...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
return nil
|
||||
@@ -56,13 +65,19 @@ func (c *Client) run(args ...string) error {
|
||||
return lastErr
|
||||
}
|
||||
|
||||
// SetAllOff sets all devices to black (off) using direct mode.
|
||||
// SetAllOff sets all devices to black (off).
|
||||
//
|
||||
// Uses "static" mode, not "direct": OpenRGB's direct-mode color path crashes
|
||||
// (vector out-of-bounds → SIGABRT) on devices that expose addressable zones
|
||||
// with zero LEDs, e.g. unused ASUS Aura ARGB headers. Static mode applies the
|
||||
// same color across all devices and zones without hitting that path.
|
||||
func (c *Client) SetAllOff() error {
|
||||
return c.run("--mode", "direct", "--color", "000000")
|
||||
return c.run("--mode", "static", "--color", "000000")
|
||||
}
|
||||
|
||||
// SetAllOn sets all devices to the given color.
|
||||
// SetAllOn sets all devices to the given color. See SetAllOff for why this uses
|
||||
// "static" mode rather than "direct".
|
||||
func (c *Client) SetAllOn(r, g, b byte) error {
|
||||
color := fmt.Sprintf("%02X%02X%02X", r, g, b)
|
||||
return c.run("--mode", "direct", "--color", color)
|
||||
return c.run("--mode", "static", "--color", color)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user