#!/usr/bin/env python # -*- coding: utf-8 -*- import time, os, sys, signal, setproctitle, traceback MIN_TEMP = 50 # fan starts to cool MAX_TEMP = 80 # fan cooling full power def call_acpi(command): acpi_call = open('/proc/acpi/call', 'w') acpi_call.write(command) acpi_call.close() # Response acpi_call = open('/proc/acpi/call') response = acpi_call.read() acpi_call.close() return response def set_fan(speed, fan=1): if speed < 0: speed = 0 elif speed > 100: speed = 100 raw_speed = round(speed * 2.55) call_acpi('\_SB.PCI0.LPCB.EC0.SFNV %d %s' % (fan, raw_speed)) print('Set fan speed to %d %%' % speed) def get_cpu_temp(): return int(call_acpi('\_SB.PCI0.LPCB.EC0.ECPU')[:4], 16) # you can adjust the fan behavior with any mathematic function # for example you can use a square function "return temp**2* or cubic "return temp**3" def scale_temp(temp): return temp def handle_fan(current_temp): temp_range = MAX_TEMP - MIN_TEMP norm_temp = current_temp - MIN_TEMP if (current_temp - MIN_TEMP) > 0 else 0 scaled_temp = scale_temp(norm_temp) scaled_border = scale_temp(temp_range) fan_speed = 100/scaled_border * scaled_temp # in percent print("Current CPU temperature %d°" % current_temp) set_fan(fan_speed, 1) set_fan(fan_speed, 2) def cleanup(signal=None, frame=None): call_acpi('\_SB.PCI0.LPCB.EC0.SFNV 0 0') call_acpi('\_SB.ATKD.QMOD 0x02') print('\nReset fan control to automatic. Exiting...') sys.exit(0) def main(): signal.signal(signal.SIGTERM, cleanup) try: while True: handle_fan(get_cpu_temp()) time.sleep(2) except: traceback.print_exc() finally: cleanup() if __name__=='__main__': # TODO: only one instance setproctitle.setproctitle('fancontrol') main(