Last active
October 17, 2019 19:22
-
-
Save jeremy-wolfe/4c5ba83a455f277b86d36f7639a32eb9 to your computer and use it in GitHub Desktop.
Automatic low-speed fan control for Dell PowerEdge systems via IPMI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/* | |
Automatic low-speed fan control for Dell PowerEdge systems via IPMI | |
https://gist.github.com/CaptainVascular/4c5ba83a455f277b86d36f7639a32eb9 | |
MIT License | |
Tested on R710 only | |
Requires nodejs, lm_sensors, ipmitool, freeipmi | |
*/ | |
// Manual fan speed % | |
const manualSpeed = 5; | |
// CPU temp max threshold % | |
// Go to auto fan speed if current temp of any core is this % of the sensor "max" as output by the "sensors" command | |
const cpuThresh = 50; | |
// Ambient max temp in degrees C | |
// Go to auto fan speed if current ambient temp is >= this temp | |
const ambientMax = 35; | |
// Sensor ID number for ambient temperature, from output of ipmi-sensors | |
const ambientId = 5; | |
// Poll time in seconds | |
const poll = 10; | |
// =================================================================== | |
const {execSync} = require('child_process'); | |
let isAuto = true; | |
let manualSpeedHex = manualSpeed.toString(16); | |
if (manualSpeedHex.length < 2) manualSpeedHex = '0' + manualSpeedHex; | |
const cpuThreshDec = cpuThresh / 100; | |
function setAuto(auto, message) { | |
if (!auto) auto = false; | |
if (isAuto === auto) return; | |
isAuto = auto; | |
if (message) console.log(message); | |
console.log(`Setting speed to ${auto ? 'auto' : manualSpeed + '%'}`); | |
execSync('ipmitool raw 0x30 0x30 0x01 0x0' + (auto ? '1' : '0')); | |
if (!auto) execSync('ipmitool raw 0x30 0x30 0x02 0xff 0x' + manualSpeedHex); | |
} | |
function T(degrees) { | |
return `${degrees}°C / ${Math.round(degrees * 1.8 + 32)}°F`; | |
} | |
process.on('exit', () => { | |
setAuto(true, 'Exiting'); | |
}); | |
process.on('SIGHUP', process.exit); | |
process.on('SIGTERM', process.exit); | |
process.on('SIGINT', process.exit); | |
process.on('SIGUSR1', process.exit); | |
process.on('SIGUSR2', process.exit); | |
process.on('uncaughtException', process.exit); | |
setInterval(() => { | |
const ambientRaw = execSync(`ipmi-sensors -r ${ambientId} --no-header-output`); | |
const ambientParts = ambientRaw && ambientRaw.toString().split('|').map((part) => part.trim()); | |
const ambient = ambientParts && ambientParts[3] && parseInt(ambientParts[3]); | |
if (!ambient) return setAuto(true, 'Could not read ambient temp'); | |
if (ambient >= ambientMax) return setAuto(true, `Ambient Current: ${T(ambient)}, Max: ${T(ambientMax)}`) | |
const readingsRaw = execSync('sensors -j'); | |
const readings = readingsRaw && JSON.parse(readingsRaw.toString()); | |
for (const dev in readings) { | |
for (const core in readings[dev]) { | |
if (!/^Core/.test(core)) continue; | |
const tempsRaw = readings[dev][core]; | |
const temps = {}; | |
for (const temp in tempsRaw) temps[temp.replace(/^temp\d*_/, '')] = tempsRaw[temp]; | |
if (!temps.max) return setAuto(true, `Could not read ${core} max temp`); | |
const max = Math.round(temps.max * cpuThreshDec); | |
if (temps.input >= max) return setAuto(true, `${core} Current: ${T(temps.input)}, Max: ${T(temps.max)}, Thresh: ${T(max)} (${cpuThresh}%)`); | |
} | |
} | |
setAuto(false, 'No temperatures above thresholds'); | |
}, poll * 1000); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=Dell PowerEdge fan control | |
[Service] | |
ExecStart=/usr/local/bin/ipmi-dell-fans | |
[Install] | |
WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment