You are not logged in.

#1 2014-09-06 10:11:20

fishman
Member
Registered: 2010-02-23
Posts: 6

[SOLVED] Fan control with ACPI for e.g. ASUS U30JC

Hi guys,

I have an ASUS U30JC for which lm_sensors is unable to detect my fan and that I can control it. After research I found a guy who solved the fan problem for an ASUS Zenbook with ACPI (http://forum.notebookreview.com/asus/70 … x32vd.html). I ported the approach with ACPI to my laptop, because it is fairly general.

You may need to modify the ACPI commands (probably the namespace of the actual command) for another device. For example I needed to replace "\_SB.PCI0.LPCB.EC0.SFNV" with "\_SB.PCI0.SBRG.EC0.SFNV".
You can get the ACPI specification (https://wiki.archlinux.org/index.php/DSDT) by:

1.) Extract ACPI tables (as root): # cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
2.) Decompile: iasl -d dsdt.dat

Search for e.g. SFNV and adapt the "namespace/path".

# fancontrol.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time, os, sys, signal, setproctitle, traceback

MIN_TEMP = 70 # fan starts to cool
MAX_TEMP = 95 # 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.SBRG.EC0.SFNV %d %s' % (fan, raw_speed))
    
    print('Set fan speed to %d %%' % speed)
    
def get_cpu_temp():
    return int(call_acpi('\_SB.PCI0.SBRG.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)
    
def cleanup(signal=None, frame=None):
    call_acpi('\_SB.PCI0.SBRG.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()

You need acpi_call and python-setproctitle (AUR, optional).
setproctitle and traceback is optional for better handling/debugging you can comment it if you want to.

It's more a proof of concept but it works for me and I am very happy now big_smile
Important think about minimum and maximum temperature!

You can change the fan behavior in "scale_temp(temp)": linear, square, cubic, ... whatever you want.

On exiting or terminating the automatic mode is activated again (which does not work SIGKILL of course).

Hope it works for you and I think it should work on other laptops with small modifications (ACPI commands).
Feel free to modify and adjust my script smile

Best regards,

fishman

Offline

#2 2015-06-29 18:09:57

Chocobozzz
Member
Registered: 2015-06-29
Posts: 1

Re: [SOLVED] Fan control with ACPI for e.g. ASUS U30JC

Thanks a lot it works on my UX501JW smile

Offline

Board footer

Powered by FluxBB