Skip to main content

Powering Down the Idle GPU: Wake-on-LAN AI Orchestration

James Bolton

Powering Down the Idle GPU: Wake-on-LAN AI Orchestration

Glavin! If you are running high-performance models on a separate GPU rig, you know the frustration: either you leave it running 24/7 (wasting power) or you spend half your time manually managing power states.

I’ve engineered a compact solution: a Python orchestration proxy. It uses Wake-on-LAN (WoL) to fire up your GPU rig, waits for your inference API (e.g., LM Studio) to initialize, launches your Hermes session, and implements an SSH-powered sleep watchdog to kill the power after 10 minutes of inactivity.

The Architecture

`text

User ──> Proxy (WoL + SSH) ──> GPU Rig (Model API)

`

The Orchestrator

This script replaces your standard hermes CLI invocation:

`python

import os

import sys

import time

import socket

import threading

import subprocess

import paramiko

from wakeonlan import send_magic_packet

--- Configuration ---

PC_MAC = "AA:BB:CC:DD:EE:FF"

PC_IP = "192.168.1.50"

LM_STUDIO_PORT = 1234

SSH_USER = "username"

SSH_KEY_PATH = os.path.expanduser("~/.ssh/id_rsa")

INACTIVITY_TIMEOUT_SEC = 600

Windows: "rundll32.exe powrprof.dll,SetSuspendState 0,1,0"

Linux: "sudo systemctl suspend"

REMOTE_SLEEP_CMD = "rundll32.exe powrprof.dll,SetSuspendState 0,1,0"

class HostManager:

def __init__(self):

self.last_activity = time.time()

self.stop_event = threading.Event()

def update_activity(self):

self.last_activity = time.time()

def wake_host(self):

print(f"[*] Sending Magic Packet to {PC_MAC}...")

send_magic_packet(PC_MAC)

print("[*] Waiting for API to come online...", end="", flush=True)

while not self.stop_event.is_set():

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:

s.settimeout(2)

try:

if s.connect_ex((PC_IP, LM_STUDIO_PORT)) == 0:

print("\n[+] Host is awake!")

self.update_activity()

return True

except Exception: pass

print(".", end="", flush=True)

time.sleep(2)

return False

def put_host_to_sleep(self):

print("\n[*] Sending sleep command via SSH...")

try:

ssh = paramiko.SSHClient()

ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

ssh.connect(PC_IP, username=SSH_USER, key_filename=SSH_KEY_PATH, timeout=5)

ssh.exec_command(REMOTE_SLEEP_CMD)

ssh.close()

print("[+] Sleep command delivered.")

except Exception as e: print(f"[-] Failed: {e}")

def idle_watchdog(self):

while not self.stop_event.is_set():

time.sleep(10)

if time.time() - self.last_activity >= INACTIVITY_TIMEOUT_SEC:

self.put_host_to_sleep()

self.stop_event.set()

break

def main():

manager = HostManager()

if not manager.wake_host(): sys.exit(1)

threading.Thread(target=manager.idle_watchdog, daemon=True).start()

try:

process = subprocess.Popen(["hermes"] + sys.argv[1:])

while process.poll() is None:

manager.update_activity()

time.sleep(2)

finally:

manager.stop_event.set()

if input("\nPut host to sleep? [Y/n]: ").strip().lower() in ("", "y"):

manager.put_host_to_sleep()

if __name__ == "__main__":

main()

`

Turning it into a Skill

To make this truly useful for a daily coding workflow, I’ve packaged this into a Hermes Skill called wol-orchestrator.

Instead of manual execution, I now trigger tasks by invoking the skill from my main terminal:

`bash

hermes terminal --command "python ~/scripts/hermes_orchestrator.py --task 'Refactor the authentication middleware'"

`

This delegates the entire lifecycle—power management, API readiness, and cleanup—directly to the agent. No more manual power toggling. Efficiency!


More Stories

Coding with a ZX Spectrum with VS Code - Part 1

As a web developer, I wondered, can I code a game with a more modern IDE

My first Arduino project

My first go at a simple circuit.

Subscribe to the newsletter

Get an email whenever a new post is published. No spam, unsubscribe at any time.