Notes and tools for controlling the Cloud Alpha 2 base station ("puck") lighting on Linux and Windows without NGENUITY: a steady dim ring and dimmed button LEDs, stored on the device, so nothing has to keep running on the PC.
| What | State | Where it lives |
|---|---|---|
| Ring brightness | 5 / 255 (~2%) | Settings sector 0x1F000 |
| Ring color | Steady white | Stored frame at 0x17C00, ring idle mode 6 (written 2026-09-29; survives unplug/replug) |
| Button LEDs | 10% of the original colors | Settings sector 0x1F000 |
Button colors (original → now):
| Button | Original | Now |
|---|---|---|
| top-left | (60, 10, 90) | (6, 1, 9) |
| top-middle | (0, 30, 200) | (0, 3, 20) |
| top-right | (24, 255, 240) | (2, 26, 24) |
| bottom-left | (200, 20, 0) | (20, 2, 0) |
| bottom-middle | (247, 173, 0) | (25, 17, 0) |
| bottom-right | (60, 220, 20) | (6, 22, 2) |
Button colors and brightness were first written with peroxy/hyperx-cloud-alpha2-lightsout. Starting NGENUITY resets the brightness to 100% and the buttons to the original colors (and probably the ring mode too), so keep its auto-launch off.
Full details, with firmware addresses as evidence:
docs/firmware-protocol.md: every command the base station firmware accepts, the flash map and the ring effect engine (static analysis of the firmware).docs/ngenuity-protocol.md: how NGENUITY 3.0.2 encodes the same commands (generic HyperX protocol), effect ids, and what it uses for this device.
NGENUITY ships it: %LOCALAPPDATA%\NGENUITY\current\Assets\Services\Libs\Outlaw\.
| File | Device |
|---|---|
03F008BE.hex |
Base station controller (Sonix SN32F24xC, Cortex-M0, code 0x0–0xC103) |
03F00ABE.bin |
Wireless radio (Airoha) |
03F00BBEA.bin, 03F00BBEP.bin |
Headset (Airoha) |
NGENUITY flashes the base station through the Sonix ISP bootloader (SnxHidLib.dll,
code security 0), so this .hex is exactly what runs on the puck.
The firmware and NGENUITY files are not in this repo: the NGENUITY EULA forbids
redistributing them. docs/sources.md records the exact package,
download URL, file paths and SHA-256 hashes, and tools/extract-firmware.sh recreates the
local analysis files (in the git-ignored fw/) from HyperX's own package.
| USB ID | What |
|---|---|
03f0:08be |
Base station controller: lighting, buttons, dial. Vendor HID on interface 2 (usage page 0xFF13), 64-byte reports, first byte = report ID = command |
03f0:0abe |
Wireless radio (audio) |
03f0:0bbe |
Headset over the USB cable |
0c45:7160 |
Sonix mask-ROM ISP bootloader the base station re-enumerates as |
Every request is padded to 64 bytes. The puck acks each one with FF 01 … [0x0e]=cmd [0x0f]=sub (FF 02 = error or unknown), and some also send a reply report (first byte
= cmd + 1). ⚠ = writes flash.
| Bytes | Meaning |
|---|---|
40 01 S 00 LL |
Ring brightness LL. ⚠ saved only if S = 01 |
40 02 |
Read brightness → 41 02 LL |
42 02 01 00 MM PL PH |
⚠ Ring idle mode MM and effect period (PH<<8|PL, 0 = keep). Always saved |
42 03 |
Read effect period → 43 03 00 PL PH (default 50) |
44 01 NP |
Start a live frame of NP packets (NGENUITY: 44 01 02) |
44 02 II 00 [R G B]×20 |
Live frame packet II (21 ring LEDs: 20 in packet 0, 1 in packet 1) |
44 03 NF CL CH 01 |
Open a flash upload of NF frames / CL|CH<<8 packets |
44 04 IL IH [R G B]×20 |
⚠ Upload packet IH<<8|IL to 0x17C00 + idx×0x40 (packet 0 erases the 1 KB sector). Raw flash writer: never send indexes beyond the upload |
44 03 01 01 00 02 + 44 04 00 00 [R G B]×6 + 42 02 02 00 06 |
⚠ Stage and save the six button colors (lightsout) |
44 05 |
Read stored animation header → 45 05 00 02 (1 frame, 2 packets) or FF FF (none) |
44 06 01 IL IH |
Read flash page 0x17C00 + idx×0x40, bytes 4..63 only |
Ring idle modes (what the ring shows when no live frames arrive for 2 s):
| Mode | Effect |
|---|---|
| 3 | Factory default: rotating wave from a 64-color palette stored at 0x1F004 |
| 6 | Play the animation stored at 0x17C00 (one frame = static color) |
| 7, 8 | Temporary level bar for headset events (volume) |
| other (e.g. 0) | Draw nothing, so the ring keeps its last frame |
Other notes:
- The brightness scales all ring output, including stored frames.
- Frames are ignored for ~0.5 s after boot and while the mic-mute flag is set.
- Button colors are stored as B,R,G at
0x1F104. Pure black(0,0,0)is skipped by the firmware, so "off" is(1,1,1). 0x1E400holds a factory-default copy of the settings (restored by the factory-reset report07 02 ff; don't send report IDs01or07casually).- Headset battery: send
50 02; the base station relays it to the headset and answers51 02 PP 00 xx 00 FF …, wherePPis the percentage and bit 7 ofFFmeans charging (layout from HaloBattery PR #127; confirmed 2026-09-29:51 02 57 …= 87%). Anfb 13 00 PPreport with the same percentage comes along.52 01→53 01 01looks like a connection status (unconfirmed).
Flash backup taken first (fw/flash-backup-2026-09-29.txt, all 528 data pages). Then:
44 03 01 02 00 01 -> FF 01
44 04 00 00 [FF FF FF]×20 -> 45 04 00 00 00
44 04 01 00 FF FF FF -> 45 04 01 00 00
44 05 -> 45 05 00 02
42 02 01 00 06 00 00 -> FF 01
Afterwards brightness, effect period and all settings pages read back identical to the
backup. After unplugging and replugging, the ring came back white with nothing running on the
PC. Undo: 42 02 01 00 03 00 00 (back to the rainbow wave).
One program with a settings window and a command line. Rust workspace: crates/alpha2 is
the device library (no dependencies), crates/alpha2-app the alpha2 program (egui with
OpenGL, ~5.8 MB; on Windows the C runtime is linked statically, see .cargo/config.toml,
so the .exe runs on its own). Everything is stored on the base station, so nothing has to
keep running afterwards.
cargo build --release # -> target/release/alpha2(.exe)
Settings window: double-click alpha2.exe, or run alpha2 / alpha2 gui. It is a
console program with an embedded manifest (consoleAllocationPolicy = detached), so a
double-click opens no console window on Windows 11 24H2 and later (older Windows: a brief
flash). It shows the headset battery (refreshed every 30 s), reads the stored settings, previews ring color and brightness live on the device, and only writes
flash when you click Save to device (only what changed). Closing without saving
restores the stored brightness. ~80 MB RAM while open (mostly the OpenGL driver).
Command line:
alpha2 status # battery, brightness, effect period, stored ring, button colors
alpha2 battery # headset battery, e.g. "87%" or "87% (charging)"
alpha2 ring static ffffff # ⚠ store a static ring color (or 21 colors, one per LED)
alpha2 ring rainbow # ⚠ back to the factory rainbow wave (--period N, lower = faster)
alpha2 ring off # ⚠ ring off
alpha2 ring preview ff0000 5 # show a color for 5 s without storing anything
alpha2 brightness 5 # ⚠ ring brightness 0-255 or 2% (--no-save: until power-off)
alpha2 buttons 060109 000314 021a18 140200 191100 061602 # ⚠ top-left ... bottom-right
alpha2 backup # dump the readable flash data area to a text file
⚠ = writes the base station's flash. Tested on the device (2026-09-29): all read commands,
backup, ring preview, the write paths of brightness, ring static and buttons, and
saving ring color, brightness and a button color from the settings window. Not yet run:
ring rainbow and ring off.
On Linux, install linux/70-hyperx-alpha2.rules so it works without root. If the old
Python ring service (hyperx-alpha2-ring.service) is still installed on a Linux machine,
disable it: it is no longer needed.
tools/extract-firmware.sh gets the base station firmware from HyperX's NGENUITY package
for analysis (see docs/sources.md).
- USB passthrough (virt-manager host device): Windows' transfers to the base station hang for about 34 s and get cancelled. Doesn't work.
- SPICE USB redirection: sending works, but no replies come back, so NGENUITY shows the headset as "stealth". Use native Windows (Wireshark + USBPcap) for captures.
- Its "Static" ring is a software effect: the light engine streams frames 5 times a second. NGENUITY never uses the firmware's onboard modes for this device's ring.
40 01 00 00 LLdoes not save by itself. It only persisted because lightsout's42 02 02commit saves the whole settings sector.
- Sapd/HeadsetControl (C, GPL-3.0): the big multi-brand CLI (battery, sidetone, lights, chatmix, EQ, ...), with separate GUI companion projects. HyperX: Cloud Alpha Wireless, Cloud Flight Wireless, Cloud II Wireless. No Cloud Alpha 2.
- LennardKittner/HyperHeadset (Rust, MIT): HyperX-only CLI + tray app (battery, mute, sidetone, EQ, ...) for Cloud II/III, Stinger 2, Flight, Alpha Wireless and more. No lighting, no Cloud Alpha 2.
- HeyOkay/HaloBattery: battery monitor. Its open
PR #127 adds the Cloud Alpha 2 battery over the base station (
50 02), which is where our battery command comes from. - OpenRGB: no Alpha 2 device or issue. Nobody else controls the Alpha 2 lighting.
- Click through the GUI (preview, save, revert) and test
ring rainbow,ring offand new button colors on the device. - Per-LED ring colors and multi-frame stored animations in the GUI.
- Other headset-side settings relayed by the puck (mute, sidetone, EQ:
60 xx,62 xx,66 xx), and Alpha 2 support in HyperHeadset or HeadsetControl. - PR the stored-ring method to lightsout.