Arista - Custom Fan Speed Controller
Arista - Custom Fan Speed Controller#
Problem#
The automatic fan speed controller is too conservative which leads to a lot of noise coming out of my switch. For instance, in an ambient temperature of 15℃ the fan is running at 60% which is absurd.
Solution#
The solution is to run a custom Python script that controls the speed of the fans based on the temperature of the system.
Python script#
#!/usr/bin/env python
import json
import logging
import logging.handlers
import time
from EapiClientLib import EapiClient
# --- Configure Logging ---
# Set up a logger to send messages to the local syslog service
logger = logging.getLogger("FanControlScript")
logger.setLevel(logging.INFO) # Set the minimum level of messages to log
# The SysLogHandler sends logs to the standard '/dev/log' socket
handler = logging.handlers.SysLogHandler(address="/dev/log")
# Add a formatter to make the log messages clean
formatter = logging.Formatter("%(name)s: %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
# --- End Logging Configuration ---
# Use this to connect to the switch's eAPI
switch = EapiClient(disableAaa=True)
# --- Define Your Custom Algorithm Here ---
# Temperature sensor to monitor. Sensor '9' (Switch Bottom Right Inner) is a good choice.
SENSOR_TO_WATCH = "9"
# Define temperature thresholds (in Celsius) and corresponding fan speeds (in percentage).
TEMP_THRESHOLDS = {
50: 70, # If temp is over 50C, set fans to 70%
45: 50, # If temp is between 45C and 50C, set fans to 50%
40: 35, # If temp is between 40C and 45C, set fans to 35%
0: 30, # If temp is below 40C, set fans to 30% (base speed)
}
CRITICAL_TEMP = 75
CHECK_INTERVAL = 30
def get_current_temp(sensor_id):
"""Gets the temperature from a specific sensor."""
try:
response = switch.runCmds(1, ["show environment temperature"], "json")
sensors = response["result"][0]["tempSensors"]
for sensor in sensors:
if sensor["name"].endswith(sensor_id):
return sensor["currentTemperature"]
return None # Sensor not found
except Exception as e:
logger.error("Error getting temperature: %s", e)
return 99 # Return safe high value on error
def set_fan_speed(speed):
"""Sets the fan speed using a flat list of sequential commands."""
logger.info("Setting fan speed to %s%%", speed)
cmd = "environment fan-speed override {}".format(speed)
try:
switch.runCmds(1, ["enable", "configure", cmd, "exit"], "text")
except Exception as e:
logger.error("Error setting fan speed: %s", e)
if __name__ == "__main__":
logger.info("Starting custom fan control script...")
current_speed = 0
try:
response = switch.runCmds(1, ["show environment cooling"], "text")[0]["output"]
for line in response.split("\n"):
if "Fan speed override mode enabled at" in line:
current_speed = int(line.split("%")[0].split()[-1])
logger.info("Initial fan speed detected as %s%%", current_speed)
break
except Exception as e:
logger.warning("Could not detect initial fan speed. Error: %s", e)
while True:
temp_raw = get_current_temp(SENSOR_TO_WATCH)
if temp_raw is None:
logger.error("Could not find sensor %s. Exiting.", SENSOR_TO_WATCH)
set_fan_speed(80) # Set to a safe speed and exit
break
temp = int(round(temp_raw))
logger.debug("Current temperature for sensor %s is %sC", SENSOR_TO_WATCH, temp)
if temp >= CRITICAL_TEMP:
logger.critical(
"CRITICAL TEMPERATURE (%sC) DETECTED! Setting fans to 100%% and exiting.",
temp,
)
set_fan_speed(100)
break
target_speed = 0
for temp_threshold in sorted(TEMP_THRESHOLDS.keys(), reverse=True):
if temp >= temp_threshold:
target_speed = TEMP_THRESHOLDS[temp_threshold]
break
if target_speed != current_speed:
set_fan_speed(target_speed)
current_speed = target_speed
else:
# This message is useful for debugging but can be noisy, so we log it at the DEBUG level.
logger.debug("Temperature is stable. Keeping speed at %s%%.", current_speed)
time.sleep(CHECK_INTERVAL)
Install the custom fan controller#
Place the Python script within the flash partition#
Save the above script as /mnt/flash/custom_fan_control.py, feel free to use scp or vi directly on the switch.
Install it as an event-handler#
Run the following command within an Arista - Configure Terminal
! Create the event-handler and give it a name
event-handler CUSTOM-FAN-CONTROL
! Set the trigger to run after the switch boots up
trigger on-boot
! Define the command to run. We use 'sudo' for permissions,
! redirect output to a log file, and use '&' to run it in the background.
action bash nohup /usr/bin/python /mnt/flash/custom_fan_control.py &
! (Optional but Recommended) Add a delay to let the switch fully initialize
! before running the script. 300 seconds (5 minutes) is a safe value.
delay 300
end