-
Notifications
You must be signed in to change notification settings - Fork 0
/
hardware_pwm_fan
121 lines (108 loc) · 3.82 KB
/
hardware_pwm_fan
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
#!/usr/bin/python3
import getopt
import sys
import time
import sdnotify
from subprocess import check_output
from rpi_hardware_pwm import HardwarePWM
# Defaults
HARD_PWM_CHAN = 0
SLEEP_TIME = 5
OFF_TEMP = 35
MAX_TEMP = 80
FAN_LOW_PCT = 20
VERBOSE = False
NOTIFY = False
def usage():
"""Print usage information"""
print(f'Usage: {sys.argv[0]} [-hvn] --hard_pwm_channel=[0 | 1] [-off-temp=<temp>] ')
print(' [-high-temp=<temp>] [-fan-low-pct=<pct>] [-sleep=<sec>]')
print('')
print(' -h, --help Print this help')
print(' -v, --verbose Verbose output')
print(' --off-temp=<temp> Temperature at which the fan is turned off')
print(' --high-temp=<temp> Temperature at which the fan is at full speed')
print(' --fan-low-pct=<pct> How slow the fan is at the lowest speed')
print(' --hard-pwm-channel=<chan> GPIO channel to use for the hardware PWM fan')
print(' --sleep=<sec> Time to sleep between temperature checks')
print(' -n, --notify Enables systemd notify support')
print('')
print('Note: You must specify a hardware PWM channel for this to work, and')
print(' have loaded the pwm or pwm-2chan dtoverlay for the Raspberry Pi.')
print(' See /boot/overlays/README and /boot/config.txt for more info.')
print('')
def gettemp():
"""Get the current temperature"""
return float(check_output(['cat', '/sys/class/thermal/thermal_zone0/temp']).decode()) / 1000.0
def fan_speed(temp: float):
"""Calculate the fan 'curve' (not really a curve)"""
max_speed = 100
min_speed = max_speed * FAN_LOW_PCT / 100
if temp < OFF_TEMP:
return 0
elif temp > MAX_TEMP:
return max_speed
else:
# linear interpolation
return int(
min_speed + ((temp - OFF_TEMP) / (MAX_TEMP - OFF_TEMP)) * (max_speed - min_speed))
def main():
"""Main function"""
global HARD_PWM_CHAN, SLEEP_TIME, OFF_TEMP, MAX_TEMP, FAN_LOW_PCT, VERBOSE, NOTIFY
try:
opts, _ = getopt.getopt(sys.argv[1:], 'hv', ['off-temp=', 'high-temp=', 'fan-low-pct=',
'hard-pwm-channel=', 'sleep=', 'verbose', 'notify'])
except getopt.GetoptError as err:
print(err)
print('')
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ('-h', '--help'):
usage()
sys.exit()
elif opt in ('-v', '--verbose'):
VERBOSE = True
elif opt in ('--off-temp'):
OFF_TEMP = int(arg)
elif opt in ('--high-temp'):
MAX_TEMP = int(arg)
elif opt in ('--fan-low-pct'):
FAN_LOW_PCT = int(arg)
elif opt in ('--hard-pwm-channel'):
HARD_PWM_CHAN = int(arg)
elif opt in ('--sleep'):
SLEEP_TIME = int(arg)
elif opt in ('-n', '--notify'):
NOTIFY = True
print('')
print(f'HARD_PWM_CHAN: {HARD_PWM_CHAN}')
print(f'SLEEP_TIME: {SLEEP_TIME}')
print(f'OFF_TEMP: {OFF_TEMP}')
print(f'MAX_TEMP: {MAX_TEMP}')
print(f'FAN_LOW_PCT: {FAN_LOW_PCT}')
print(f'VERBOSE: {VERBOSE}')
print(f'NOTIFY: {NOTIFY}')
print('')
pwm = HardwarePWM(HARD_PWM_CHAN, hz=25000)
pwm.start(100)
if NOTIFY:
systemd = sdnotify.SystemdNotifier()
systemd.notify('READY=1')
try:
while True:
temp = gettemp()
speed = fan_speed(temp)
pwm.change_duty_cycle(speed)
if VERBOSE:
print(f'Temp: {temp:.1f}C, Speed: {speed}%')
if NOTIFY:
systemd.notify('WATCHDOG=1')
time.sleep(SLEEP_TIME)
except KeyboardInterrupt:
pwm.stop()
print('')
print('Exiting on KeyboardInterrupt')
sys.exit()
if __name__ == '__main__':
main()