Skip to content

Jontya/RGBController

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rgbctl — lightweight Windows RGB controller

A minimal, OpenRGB-inspired RGB controller for Windows 11. Built to control one specific rig with the smallest footprint and least input lag possible:

Device Transport Admin required
ASRock X870 Pro RS mobo + Thermalright AIO ARGB USB HID (Polychrome, VID 26CE) no
ADATA XPG Lancer Blade DDR5 RAM SMBus via PawnIO (AMD PIIX4) yes
ASRock RX 9070 XT GPU AMD GPU I2C via ADL (atiadlxx.dll) no (needs Adrenalin)

The GPU is not supported by OpenRGB. Protocol is derived from SignalRGB's ASRock GPU.js, driven here over AMD's ADL I2C interface.


Design

  • Python + CustomTkinter + pystray — modern dark-mode UI, tiny bundle, no extra runtime.
  • One backend interface (core/device.py): every device is a Device with Zones and a single apply(). The UI, presets, and effect engine never special-case hardware — adding a device is one backend class.
  • One effect engine (core/engine.py): static mode writes once and idles at 0% CPU (key for the always-on case); animated modes run a single 30 Hz loop for all devices.
  • One-shot + tray hybrid: --apply-quit applies the boot preset and exits (near-zero idle RAM); launch the full app only to change settings.

Windows — first-time setup

1. Prerequisites

  • Python 3.11+python.org. During install tick "Add python.exe to PATH".
  • AMD Adrenalin — required for GPU ADL I2C (atiadlxx.dll). Install via AMD's site or auto-install driver package.
  • Close SignalRGB before running rgbctl — if it is open its own render loop overwrites every write to the GPU and colors will not change.

2. Clone and install deps

git clone <repo-url> rgbctl
cd rgbctl
pip install -r requirements.txt

3. PawnIO (RAM RGB only — optional)

DDR5 RGB needs kernel-level SMBus access through PawnIO. Skip this block if you don't need RAM control — the app runs fine without it.

  1. Install PawnIO (official, signed edition): pawnio.eu → Download → run PawnIO_setup.exe.

  2. Download SmbusPIIX4.bin from PawnIO.Modules releases.

  3. Place SmbusPIIX4.bin in the modules/ folder inside the repo.

  4. Pin its hash (required — the app refuses to load an unsigned/unverified module):

    # run from the repo root in PowerShell:
    (Get-FileHash modules\SmbusPIIX4.bin -Algorithm SHA256).Hash.ToLower() `
      | Out-File -Encoding ascii -NoNewline modules\SmbusPIIX4.bin.sha256

4. Run

python main.pyw                # full window (tray-resident)
python main.pyw --minimized    # start hidden in tray
python main.pyw --apply-quit   # apply startup preset, exit (boot path)

Dev / cross-platform: RGBCTL_MOCK=1 python main.pyw runs with simulated devices on any OS (WSL, Linux, macOS) — no hardware or Windows DLLs required.


Build a Windows exe

Produces a --onedir bundle in dist/rgbctl/ via PyInstaller. --onedir starts faster than --onefile (no per-launch extraction) — important for the --apply-quit boot path.

pip install pyinstaller
python build.py

The build script verifies SmbusPIIX4.bin against its pinned SHA-256 before bundling — a tampered module aborts the build rather than shipping in a release.

To add a Windows Startup entry (apply-and-exit at login):

from rgbctl.autostart import install
install()

This creates a plain non-admin Startup shortcut (--apply-quit). No scheduled task, no UAC bypass — see Security section.


UI

The interface uses CustomTkinter for a native dark-mode look on Windows 11.

  • Sidebar: device list, preset picker (save/load), mode selector, speed slider.
  • Device panel: inline HSV colour picker (wheel + brightness bar) embedded directly above the zone grid — no separate dialog. Drag the wheel to pick hue/saturation; drag the brightness bar to adjust value.
  • Zone cards: each card shows the zone name, current colour swatch, an Enabled checkbox (affects engine output) and a Selected checkbox (targets colour picker). Select All button top-right of the zone grid.
  • Colour picker: applies instantly to every selected zone as you drag.
  • Tray icon: minimise-to-tray on window close. Right-click for preset shortcuts and quit. Consistent icon across tray, taskbar, and title bar.

Startup behaviour

On launch the app checks (in order):

  1. startup_preset setting → apply and optionally exit (--apply-quit).
  2. last_preset (persisted to settings.json on every manual load) → apply silently.
  3. Neither set → skip; hardware holds whatever state it was in.

No hardware write happens at launch unless a preset is found.


Security

This app does kernel-level SMBus I/O and raw GPU I2C; mistakes can corrupt hardware. Controls are documented at each call site.

  1. PawnIO / signed module: the app refuses to load SmbusPIIX4.bin unless a matching *.bin.sha256 sidecar is present. Missing or mismatched hash → fail closed; RAM control disabled, app still runs.
  2. SMBus write allowlist (brick prevention): DDR5 SPD EEPROM lives at 0x50–0x57 on the same bus — a stray write can permanently corrupt RAM and prevent boot. hw/pawnio_smbus.py rejects every write outside 0x70–0x77, enforced at the lowest method so no caller can bypass it. Verified by tests/test_smbus_guard.py.
  3. Least privilege: USB HID and GPU I2C need no admin; only RAM SMBus does.
  4. Autostart: plain non-admin Startup shortcut (--apply-quit). No auto-elevated scheduled task — Defender flags that pattern as an escalation vector.
  5. GPU validation: ADL validates ASRock subvendor 0x1849 and probes address 0x36 before any write. Save-to-Hardware (NVRAM flash) is an explicit user action only — never triggered during normal colour changes.
  6. Presets: JSON only (never pickle), schema-validated and value-clamped on load.
  7. Supply chain: runtime deps are version-pinned in requirements.txt.

Run the security test suite (no hardware needed):

python -m pytest tests/test_smbus_guard.py -q

Hardware notes

GPU (RX 9070 XT Steel Legend) — working

  • Transport: ADL I2C via ADL2_Display_WriteAndReadI2C, OEM line 1, address 0x6C.
  • Primary adapter index 5 (from ADL2_Adapter_Primary_Get) — not enum index 0.
  • Active zones: Top Side (channel 6), Fan (channel 7). No physical ARGB header on this card.
  • Protocol: init sequence + 12-byte colour packet per zone, 20 ms between zones.
  • SignalRGB must be closed — its render loop overwrites every write.

Polychrome USB (X870 Pro RS) — working

  • Disconnected zones excluded at probe: 0x02 (ARGB Header 1), 0x07 (Audio/ARGB Header 3).
  • ARGB header zones (0x03) use GRB wire order; all other zones use RGB. RGSWAP_CFG register returns 0 for all zones on this board and is not used for ordering decisions.

RAM (ADATA XPG Lancer Blade DDR5) — working (needs PawnIO)

  • SMBus via PawnIO AMD PIIX4. Write allowlist enforced: 0x70–0x77 only.

Layout

rgbctl/
  core/      device, color+effects, engine, registry, presets
  backends/  polychrome_usb, asrock_gpu_adl, ene_dram_smbus, mock
  hw/        pawnio_smbus (SMBus trust boundary), adl_i2c (GPU)
  ui/        app (window), tray, color_picker
  main.py    entrypoint (--apply-quit / --minimized / gui)
modules/     SmbusPIIX4.bin + pinned hash (gitignored — set up manually)
tests/       test_smbus_guard.py (security gate)

About

Custom lightweight python RGB controller for windows. Allows RGB control of some devices not supported by OpenRGB (ASRock 9070XT).

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages