#!/usr/bin/env python3 import subprocess import re import sys import datetime import argparse # IPMI settings IPMIUSER = "" IPMIPW = "" IPMIEK = "0000000000000000000000000000000000000000" # Fan / temperature settings FANSPEED = 20 # percent MAXTEMP = 37 # Celsius def run_ipmi(args): base = ["ipmitool", "-I", "lanplus", "-H", IPMIHOST, "-U", IPMIUSER, "-P", IPMIPW, "-y", IPMIEK] cmd = base + args p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if p.returncode != 0: raise RuntimeError(f"ipmitool failed: {' '.join(cmd)}\n{p.stderr.strip()}") return p.stdout def log_systemd(tag, msg): try: subprocess.run(["systemd-cat", "-t", tag], input=msg + "\n", text=True, check=True) except Exception: # fallback to stdout ts_print(msg) def ts_print(msg): """ts_print message prefixed with a timestamp (YYYY-MM-DD HH:MM:SS).""" now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"{now} {msg}") def get_ambient_temp(): out = run_ipmi(["sdr", "type", "temperature"]) # find lines like "Exhuat Temp | 29 degrees C" lines = [l for l in out.splitlines() if "Exhaust" in l and "degrees" in l] if not lines: raise RuntimeError("Exhaust temperature line not found in ipmitool output") # Extract last number found in the last matching line (like the original) field = lines[-1].split("|")[4] #ts_print("Debug: field =", field) m = re.search(r"(\d{1,3})", field) if not m: raise RuntimeError("Could not parse temperature from line: " + lines[-1]) return int(m.group(1)) def main(): # parse CLI args (IPMI host can be overridden with -H/--host) parser = argparse.ArgumentParser(description="Set fan speed via IPMI") parser.add_argument("-H", "--host", default="127.0.0.1", help="IPMI host/IP (default: %(default)s)") args = parser.parse_args() global IPMIHOST # set global IPMIHOST so run_ipmi() uses the provided host IPMIHOST = args.host ts_print(f"{IPMIHOST}: Fan speed check for host {IPMIHOST}") try: temp = get_ambient_temp() ts_print(f"{IPMIHOST}: Exhaust temperature: {temp} C") except Exception as e: ts_print(f"{IPMIHOST}: Error reading temperature: {e}") sys.exit(1) speed_hex = format(FANSPEED, "x") if temp > MAXTEMP: msg = f"{IPMIHOST}:Warning: Temperature is too high! Activating dynamic fan control! ({temp} C)" log_systemd("R710-IPMI-TEMP", msg) ts_print(msg) run_ipmi(["raw", "0x30", "0x30", "0x01", "0x01"]) else: okmsg = f"{IPMIHOST}: Temperature is OK ({temp} C)" log_systemd("R710-IPMI-TEMP", okmsg) ts_print(okmsg) ts_print(f"{IPMIHOST}: Activating manual fan speeds! (requested %d%%)" % FANSPEED) run_ipmi(["raw", "0x30", "0x30", "0x01", "0x00"]) run_ipmi(["raw", "0x30", "0x30", "0x02", "0xff", "0x" + speed_hex]) if __name__ == "__main__": main()