Per-pin 12V-2x6 watchdog for ASUS ROG Astral RTX 50 cards on Linux: alerts, LACT throttle, poweroff
  • Python 93.7%
  • Shell 6.3%
Find a file
Motaphe d7364df5ca service: drop After=lactd.service
lactd ships After=multi-user.target, and this unit is WantedBy=multi-user.target,
so systemd found an ordering cycle at boot and deleted our start job. The
daemon already tolerates lactd being absent (stats/profile calls retry every 2 s).
2026-10-13 06:48:16 -04:00
.gitignore astral-connector: per-pin 12V-2x6 watchdog for ASUS ROG Astral cards on Linux 2026-10-13 00:57:32 -04:00
astral-connector.service service: drop After=lactd.service 2026-10-13 06:48:16 -04:00
astral-connector.user.service System service, community-aligned tiers, event log and post-shutdown report 2026-10-13 01:26:32 -04:00
astral_connector.py selftest: expand ~ in ntfy_env before the access check 2026-10-13 01:26:53 -04:00
config.example.toml System service, community-aligned tiers, event log and post-shutdown report 2026-10-13 01:26:32 -04:00
install-system.sh System service, community-aligned tiers, event log and post-shutdown report 2026-10-13 01:26:32 -04:00
LICENSE astral-connector: per-pin 12V-2x6 watchdog for ASUS ROG Astral cards on Linux 2026-10-13 00:57:32 -04:00
README.md System service, community-aligned tiers, event log and post-shutdown report 2026-10-13 01:26:32 -04:00
test_astral_connector.py System service, community-aligned tiers, event log and post-shutdown report 2026-10-13 01:26:32 -04:00

astral-connector

A per-pin 12V-2x6 (12VHPWR) watchdog for ASUS ROG Astral RTX 50 cards on Linux. It reads the card's own per-pin current sensor (the data GPU Tweak III shows as Power Detector+), keeps a history, and escalates when a pin is overloaded: desktop and phone alert, then a throttled LACT profile, then a clean poweroff.

One Python file, standard library only. It runs as a system service from boot, so the card is protected before anyone logs in, with desktop alerts delivered into whichever graphical session is active. No kernel module.

Written with an AI assistant (Claude) and tested on one card, a ROG Astral RTX 5090 OC (1043:89E3), NVIDIA 615.78.08, kernel 7.2, LACT 0.10. Read the code before trusting it with your hardware. It never writes to the sensor chip.

What it reads

The Astral carries an ITE IT8915FN at 0x2b on the GPU's first NVIDIA i2c adapter.

Register Content
0x80..0x97 6 x (u16 BE mV, u16 BE mA), reverse pin order: the first block is pin 6
0x98 an independent total-current channel, ~0.507 x the pin sum
0xa0 a 12 V channel of ~1 A, probably the PCIe slot
0x60 8 board temperatures, 0.1 °C (not per-pin)
0xc0 3 time-in-state counters (s), a lifetime odometer

Pin order is confirmed against HWiNFO by 12vhpwr-guard and matches LibreHardwareMonitor. Several Linux tools label the pins backwards.

The chip smooths its current readings: after a step change in load they take 5 to 8 s to settle, while board power reacts within half a second. Hold times below account for that.

Board power, temperatures (including every VRAM chip) and the active profile come from the LACT daemon socket.

Rules

Each condition must hold continuously for its hold time. A high pin reading only counts if board power can account for it, so one bad frame cannot trigger anything. The tiers follow what the established tools do: 12vhpwr-guard (9.5 A / 15 s, 13 A / 3 s, 16 A at once), ASUS GPU Tweak III (warns at 9.2 A, shuts down above 12.5 A), MSI GPU Safeguard+ (cuts the power limit first). Connectors melt from heat built up over minutes, so short excursions are logged, not acted on.

Rule Warning Critical (throttle) Emergency (poweroff)
per-pin current 8.8 A for 5 s 9.5 A for 15 s, or 12.5 A for 3 s 16 A for 1 s
pin voltage (>= 10 A flowing) < 11.6 V for 5 s < 11.2 V for 5 s
open pin (>= 10 A flowing) < 0.3 A for 3 s
min/max imbalance (>= 20 A) < 0.60 for 30 s
drift from your baseline (>= 15 A) > 3 pp for 60 s
sensor silent 15 s
chip power vs board power > 20 % off for 60 s
NVIDIA driver error (NVRM: Xid in the kernel log) each one

Imbalance alone only warns: every connector is somewhat uneven, and the danger is amps on one pin, which the current rules cover. All thresholds are in the config.

Escalation

  1. Warning: desktop notification, optional ntfy push, a 2-minute flight-recorder CSV.
  2. Critical: switch LACT to the safe profile and latch there. A profile change by anything else is reverted while latched. Only astral-connector reset clears it: the fault is physical.
  3. Still critical 20 s later (10 s for the 12.5 A tier): a 30 s poweroff countdown (5 s for 12.5 A), astral-connector cancel stops it. This also runs if LACT could not switch profile.
  4. Emergency: power off at once (systemctl poweroff --check-inhibitors=no).

The RTX 5090's minimum power limit is 400 W, so the safe profile caps the core clock instead. On the test card, 1500 MHz cut a 333 W load to 141 W within half a second, and the busiest pin from 5.5 A to 2.4 A.

What gets logged

Where
every reading at 1 Hz, 14 days /var/lib/astral-connector/history.db (report draws it)
every event (warnings, throttle, countdown, poweroff, reset, Xid, crash restarts) same database, astral-connector events
the 2 minutes before any escalation and before a poweroff /var/lib/astral-connector/events/*.csv, fsynced
why the PC was powered off last-action.json; reported by notification and ntfy on the next boot
a previous boot that ended without a clean shutdown (freeze, power loss) an unclean_boot event

Install

git clone https://git.motaphe.dev/Motaphe/astral-connector.git && cd astral-connector
python3 astral_connector.py setup-profile                         # creates the Pin-Safe LACT profile
sudo ./install-system.sh
astral-connector selftest

The installer copies the script to /usr/local/lib/astral-connector, links /usr/local/bin/astral-connector, puts the config in /etc/astral-connector/ (ntfy credentials in a root-only ntfy.env), migrates any user-mode state, enables astral-connector.service, verifies fresh readings and rolls back if they do not appear. Re-run it to update. Members of wheel can run reset, cancel and baseline without root.

Needs: an Astral card, the NVIDIA driver (it exposes the i2c adapters), i2c-dev loaded, LACT running. astral-connector.user.service runs it as a user service instead, for testing: it protects only while you are logged in, and logind may refuse its poweroff without an active session.

Once the card has run under load for a while, record your connector's normal per-pin shares so drift can be detected: astral-connector baseline.

Commands

Command
run [--dry-run] the daemon
tui live terminal view
status [--json] one-shot; exit code 0/1/2 for OK/warning/critical
events [--days N] event log and the latest flight records
report [--hours N] HTML charts of the history
baseline [--minutes N | --shares a,b,c,d,e,f] record the per-pin fingerprint
reset / cancel clear the latch / stop a poweroff countdown
setup-profile [--clock MHz] / selftest / test-notify setup checks

The live state is written to /run/astral-connector/state.json every half second for bars and widgets (card name, pins, peak today, temperatures, fan, last event, latch and countdown).

Limits

  • It measures current, not temperature. A green reading is not a statement about connector heat.
  • The chip smooths its readings over several seconds, so a sub-second spike is invisible to it. That is also why it is not used for instant trips.
  • A daemon that has died protects nothing. systemd restarts it without limit and its watchdog catches a hang; a crash restart raises a notification.

Credits

Register map and pin order: astral-hwmon, LibreHardwareMonitor #2168, 12vhpwr-guard, sus. The tiered response follows 12vhpwr-guard.