A minimal Windows tray app that shows battery, mute, and charging status for the HyperX Cloud Flight Wireless headset.
This project builds on the original reverse-engineering work here: https://github.com/srn/hyperx-cloud-flight-wireless.
Why this exists: it was hard to find a trustworthy app that reliably showed Cloud Flight battery info (none worked for me), and there was no ready-to-run tray executable. This repo adds a tiny Electron tray app and a packaged
.exefor Windows.
⚠️ Battery % disclaimer: As stated in the original repository, the battery percentage is only an estimate based on the device “status” report.
- All code in this repository was generated by ChatGPT; I only monitored the process and tested the results.
- Not actively maintained. I’ll only update this if it stops working while I still own a Cloud Flight.
- Tested only with HyperX Cloud Flight Wireless on Windows 11 24H2 x64.
👉 Download the latest build from Releases (HyperXTray-win32-x64.zip).
Unzip to a permanent folder (e.g., C:\Apps\HyperXTray\) and run HyperXTray.exe.
- Left-click the tray icon to open the popup.
- Right-click for the context menu and toggle Start with Windows.
- Hover the icon to see a compact tooltip (Battery / Muted / Charging).
The app is not code-signed. Windows SmartScreen may warn on first run.
- The popup should show
connectedand the right-click menu should showStatus: connected.
If you don’t see connected, the UI will keep showing “waiting for headphone” and some parts of the UI may look like an error or “not available.” - Connected but the values aren’t updating yet? Try “nudging” the device: increase/decrease volume or mute/unmute once.
This forces a fresh HID event and usually wakes the status stream. - Hovering the tray icon shows a tooltip with a compact summary.
This repo contains two parts:
- Root module (based on the original repo + small robustness tweaks) — raw HID interface to the USB receiver; emits events like
battery,muted,charging,power, etc. tray-hyperx/— a tiny Electron app that lives in the system tray and spawns a helper (sensor.js).
The helper runs the root module in a separate Node process and streams line-delimited JSON back to the UI.
- Windows 10/11 x64
- Node.js installed system-wide (recommended Node 18+ or Node 20 LTS)
The packaged tray app launches a small helper usingnode.exe. It tries common locations:C:\Program Files\nodejs\node.exeC:\nvm4w\nodejs\node.exe%PATH%(node)
- HyperX Cloud Flight Wireless headset connected via the USB receiver.
- Download the zip from Releases.
- Extract to a permanent folder, e.g.,
C:\Apps\HyperXTray\. - Run
HyperXTray.exe. - (Optional) Right-click → Start with Windows to auto-launch on login.
You can move the folder later; the Start with Windows toggle will target the current executable.
To remove: quit the tray app (right-click → Exit), disable auto-launch if enabled, and delete the folder.
The repo is structured like a mini-monorepo:
- Root: HID module (index, etc.).
tray-hyperx/: Electron tray app that depends on the root via"file:..".
git clone https://github.com/<your-user>/hyperx-cloud-flight-battery-tray.git
cd hyperx-cloud-flight-battery-tray# at repo root
npm installcd tray-hyperx
npm installcd tray-hyperx
npm startYou should see the tray icon and live updates when the headset is connected.
cd tray-hyperx
npm run pack- Output: dist\HyperXTray-win32-x64\
- Run: dist\HyperXTray-win32-x64\HyperXTray.exe
// tray-hyperx/package.json (excerpt)
{
"scripts": {
"start": "electron .",
"pack:clean": "powershell -NoProfile -ExecutionPolicy Bypass -Command \"$p=Get-Process HyperXTray -ErrorAction SilentlyContinue; if($p){$p|Stop-Process -Force}; $q=Get-CimInstance Win32_Process | ? { $_.Name -eq 'node.exe' -and $_.CommandLine -match 'sensor\\\\.js' }; if($q){$q|%{Stop-Process -Id $_.ProcessId -Force}}; Start-Sleep -s 1; if(Test-Path dist){Remove-Item -Recurse -Force dist}\"",
"pack": "npm run pack:clean && electron-packager . HyperXTray --overwrite --platform=win32 --arch=x64 --icon=icon.ico --out=dist"
}
}
- Stops a running HyperXTray.exe if present.
- Kills any node.exe whose command line includes sensor.js (the helper).
- Removes the dist\ folder to avoid locked files and stale builds.
Goal: make detection/reporting a bit more robust for Cloud Flight revisions/firmwares while keeping the original behavior and event names.
- Device detection hardened
- Prefer VID for HyperX/Kingston and known PIDs seen on Cloud Flight USB receivers.
- Fallback: if PID matching fails, detect by product name containing “cloud flight wireless”.
- Status interface discovery
- Search for the status interface with
usage = 771(Cloud Flight status) and accept a couple of usage pages observed in the wild. - If
usagePageisn’t present, fallback to the first interface exposingusage=771.
- Search for the status interface with
- Keep-alive / bootstrap write
- Send a small 20-byte write on startup and at long intervals (default ~5 min) to keep reports flowing on some receivers.
- Expanded event model (compatible)
- Emits:
power('on' | 'off') — flipsfoundaccordingly.muted(boolean) — from 2-byte mute packets.volume('up' | 'down') — from 5-byte volume packets; useful to “poke” updates.charging(boolean) — inferred from the stream.battery(percentage) — mapped from coarse status levels (estimate).unknown(raw buffer) — unrecognized packets for diagnostics.
- Emits:
- De-duplication & throttling
- Skip emitting identical values back-to-back.
batteryMinIntervalMs(tray uses 60 s) reduces spam when percentage doesn’t change.
- Startup & error surfacing
- Try opening all relevant interfaces and listen on each.
- Bubble up readable
errorevents when opening or writing fails.
Battery math remains coarse-grained. Percent jumps in steps and caps at 100% while charging. It’s an estimate, like the original.
-
Libraries
node-hid— raw HID access to the USB receiver.emittery— tiny event emitter used by the root module.- Electron — tray UI, context menu, auto-launch, and helper orchestration.
electron-packager— produces the portable Windows build.
-
Key files
- Root
index.js: HID logic + event emitter.test.js: example script logging all emitted events (power, muted, volume, charging, battery, unknown, error).
- Tray (
tray-hyperx/)main.js: Electron main process. Creates tray/popup/context menu & Start with Windows; spawnssensor.js; graceful restart/exit handling; single-instance lock.sensor.js: Runs the root module in a separate Node process and prints line-delimited JSON to stdout for the UI.tray.html/tray.css: small popup UI (Battery / Muted / Charging).icon.ico: tray icon.package.json: scripts (start,pack,pack:clean).
- Root
-
Packaging choices
- No ASAR — simpler to spawn
sensor.jswith the systemnode.exe. - Unsigned — SmartScreen may prompt on first run.
- Auto-launch — uses
app.setLoginItemSettings(...)to add/remove aRunregistry entry.
- No ASAR — simpler to spawn
-
Limitations
- Battery % is an estimate and may jump in steps.
- Requires Node.js installed (for the helper process).
- Tested only on Windows 11 24H2 x64 with Cloud Flight Wireless.
-
Privacy
- The app does not collect or send data. It only reads HID reports locally and stores your Start with Windows preference on your machine.
- Original reverse-engineering and base module by srn.
- Tray app: generated by ChatGPT; monitored and tested by me.
- License: ISC (same as the original).


