-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfan_chassis.py
executable file
·163 lines (144 loc) · 5.1 KB
/
fan_chassis.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/python3
### IMPORTANT ###
# you must enable pwm chanels in /boot/config.txt
# see https://github.com/Pioreactor/rpi_hardware_pwm
# python modules
from rpi_hardware_pwm import HardwarePWM
import time
import signal
import sys
import os
import sys, getopt
import json
# Configuration
PWM_CHANNEL = 0 # PWM channel used to drive PWM fan (gpio18 = channel 0)
WAIT_TIME = 5 # [s] Time to wait between each refresh
PWM_FREQ = 65 # [Hz] 10kHz for Noctua PWM control
# Configurable temperature and fan speed
MIN_TEMP = 55
MAX_TEMP = 75
FAN_LOW = 20
FAN_HIGH = 100
FAN_OFF = 0
FAN_MAX = 100
# logging and metrics (enable = 1)
VERBOSE = 0
NODE_EXPORTER = 0
JSON_EXPORTER = 0
# parse input arguments
try:
opts, args = getopt.getopt(sys.argv[1:],"hv",["min-temp=","max-temp=","fan-low=","fan-high=","wait-time=","help","pwm-channel=","pwm-freq=","verbose","node-exporter","json-exporter"])
except getopt.GetoptError:
print('fan.py [--min-temp=40] [--max-temp=70] [--fan-low=20] [--fan-high=100] [--wait-time=1] [--pwm-channel=0] [--pwm-freq=10000] [--node-exporter] [--json-exporter] [-v|--verbose] [-h|--help]')
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
print('fan.py [--min-temp=40] [--max-temp=70] [--fan-low=20] [--fan-high=100] [--wait-time=1] [--pwm-channel=0] [--pwm-freq=10000] [--node-exporter] [--json-exporter] [-v|--verbose] [-h|--help]')
sys.exit()
elif opt in ("-v", "--verbose"):
VERBOSE = 1
elif opt in ("--min-temp"):
MIN_TEMP = int(arg)
elif opt in ("--max-temp"):
MAX_TEMP = int(arg)
elif opt in ("--fan-low"):
FAN_LOW = int(arg)
elif opt in ("--fan-high"):
FAN_HIGH = int(arg)
elif opt in ("--wait-time"):
WAIT_TIME = int(arg)
elif opt in ("--pwm-channel"):
PWM_CHANNEL = int(arg)
elif opt in ("--pwm-freq"):
PWM_FREQ = int(arg)
elif opt in ("--node-exporter"):
NODE_EXPORTER = 1
elif opt in ("--json-exporter"):
JSON_EXPORTER = 1
print("")
print("MIN_TEMP:",MIN_TEMP)
print("MAX_TEMP:",MAX_TEMP)
print("FAN_LOW:",FAN_LOW)
print("FAN_HIGH:",FAN_HIGH)
print("WAIT_TIME:",WAIT_TIME)
print("PWM_CHANNEL:",PWM_CHANNEL)
print("PWM_FREQ:",PWM_FREQ)
print("VERBOSE:",VERBOSE)
print("NODE_EXPORTER:",NODE_EXPORTER)
print("JSON_EXPORTER:",JSON_EXPORTER)
print("")
# Get CPU's temperature
def getCpuTemperature():
res = os.popen('cat /sys/devices/virtual/thermal/thermal_zone0/temp').readline()
temp = (float(res)/1000)
return temp
# Set fan speed
def setFanSpeed(speed,temp):
pwm.change_duty_cycle(speed)
# print fan speed and temperature
if VERBOSE == 1:
print("fan speed: ",int(speed)," temp: ",temp)
# write fan metrics to file for node-exporter/prometheus
if NODE_EXPORTER == 1:
# Save a reference to the original standard output
original_stdout = sys.stdout
with open('/var/lib/node_exporter/fan-metrics.prom', 'w') as f:
# Change the standard output to the file we created.
sys.stdout = f
print('raspberry_fan_speed ',speed)
print('raspberry_fan_temp ',temp)
print('raspberry_fan_min_temp ',MIN_TEMP)
print('raspberry_fan_max_temp ',MAX_TEMP)
print('raspberry_fan_fan_low ',FAN_LOW)
print('raspberry_fan_fan_high ',FAN_HIGH)
print('raspberry_fan_wait_time ',WAIT_TIME)
print('raspberry_fan_pwm_channel ',PWM_CHANNEL)
print('raspberry_fan_freq ',PWM_FREQ)
# Reset the standard output to its original value
sys.stdout = original_stdout
f.close()
# write fan metrics to json file for Home Assistant
if JSON_EXPORTER == 1:
dFan = {
'fan_speed': speed,
'cpu_temp': temp,
'cpu_min_temp': MIN_TEMP,
'cpu_max_temp': MAX_TEMP,
'fan_speed_low': FAN_LOW,
'fan_speed_high': FAN_HIGH,
'scan_time': WAIT_TIME,
'pwm_channel': PWM_CHANNEL,
'fan_frequency': PWM_FREQ
}
jsonString = json.dumps(dFan)
jsonFile = open('/usr/share/hassio/homeassistant/files/chassis_fan.json','w')
jsonFile.write(jsonString)
jsonFile.close()
return()
# Handle fan speed
def handleFanSpeed():
temp = getCpuTemperature()
# Turn off the fan if temperature is below MIN_TEMP
if temp < MIN_TEMP:
setFanSpeed(FAN_OFF,temp)
# Set fan speed to MAXIMUM if the temperature is above MAX_TEMP
elif temp > MAX_TEMP:
setFanSpeed(FAN_MAX,temp)
# Caculate dynamic fan speed
else:
step = (FAN_HIGH - FAN_LOW)/(MAX_TEMP - MIN_TEMP)
delta = temp - MIN_TEMP
speed = FAN_LOW + ( round(delta) * step )
setFanSpeed(speed,temp)
return ()
try:
# Setup hardware PWM
pwm = HardwarePWM(pwm_channel=PWM_CHANNEL, hz=60)
pwm.change_frequency(PWM_FREQ)
pwm.start(FAN_LOW) # full duty cycle
# Handle fan speed every WAIT_TIME sec
while True:
handleFanSpeed()
time.sleep(WAIT_TIME)
except KeyboardInterrupt: # trap a CTRL+C keyboard interrupt
setFanSpeed(FAN_OFF,MIN_TEMP)