lm-sensors / lm-sensors

lm-sensors repository
https://hwmon.wiki.kernel.org/
GNU General Public License v2.0
898 stars 268 forks source link

fancontrol: allow multiple sensors to control single pwm #228

Open zdzichu opened 4 years ago

zdzichu commented 4 years ago

It would be nice to be able to use input from multiple sensors to control single pwm. I think there should be a setting to select aggregation function (like MAX() and AVG()). There were such requests in downstreams: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=570529, https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=552196

RonnySvedman commented 3 years ago

this would help watercooled systems as well as cpus with only per-core temps, although maybe not as critical, where both gpu and cpu can affect water temp, and should affect both pump and radiator fan RPMs, especially if there isn't a separate water temp reading.

Darxus commented 3 years ago

(I am not involved in this project, this is not an official response.)

I was thinking about working on this problem, and I think I have decided not to, due to a shortage of use cases. I encourage you to change my mind. And maybe this helps explain why nobody else has done it.

Initially I thought it would be great to change the speed of my case fans based on the temperatures of both my CPU and GPU. But when my case fan speeds are based directly on my CPU temperature, they audibly fluctuate more annoyingly. And I think it has no actual benefit over basing case fan speed on motherboard temperature (for me, the value of SYSTIN from /usr/bin/sensors, and temp1_input in the directory where /sys/class/hwmon/hwmon1/name contains "nct6798").

This leaves two cases where clearly there would be benefit: 1) water cooling systems where one loop cools both CPU and GPU, without a temperature sensor for the water, and 2) motherboards with multiple CPU sockets that don't have a separately controllable fan header for each? And they're just not relevant enough to my life for me to do that work.

Oh, this also leaves systems with per-core temps available. Which does not seem to include mine (AMD Ryzen 7 3700X).

If you want it, implement it, submit a patch.

7eggert commented 3 years ago

I've got a 4-core CPU with four readings, any of them might be too high. Also I'm setting up a case fan that should blow whenever any component gets too hot.

Raupinger commented 3 years ago

Let me add my two cents to this, describe why this isn't some niche problem, my Ideas on how to solve it and why, despite all of this, I'm not sure adding this feature to fancontrol would even be desirable, even if somebody was willing to spend the time building it:

Why we need more flexible fan controls I have a fairly standard ATX tower. CPU and Graphics card in their normal places. 2 Intake fans in the front, 1 exhaust at the back. my current setup is that the CPU and GPU fans are controlled by their respective on-die sensors. The top front case fan is set to idle at low RPM, all other fans are stopped in idle. The top front and back fans are set to ramp up with rising CPU temperatures since they are closest to the socket. The bottom front case fan is set to be controlled by a temperature sensor on the main board. This works well in a scenario with high load on the CPU. Air gets pulled in from the front, passes the CPU cooler and gets exhausted in the back. Good airflow. A GPU load is more problematic. When the GPU heats up, its fans start dumping hot air into the case. Triggered by the rise in ambient temperature, the bottom case fan starts blowing cool air at the Graphics card. The exhaust fan however is not spinning, since its coupled to the CPU. This leads to rather suboptimal airflow where the intake fan has to build up pressure to force hot air out of the case, ultimately hurting performance. My only option right now to improve the situation for the GPU would be to control the exhaust fan over the case temperature as well, negatively impacting the airflow under heavy CPU loads. There are also a few other components like Voltage regulators or NVME SSDs in the system that could potentially need cooling. Load on those tends to coincide with at least a moderate CPU load so its not that big of a concern in practice. Still, I would prefer being able to actively cool those components if they needed it.

Dreaming about a perfect world Ideally fans would have a curve for each sensor in the system, choosing the highest RPM any curve currently demands. In my example this would allow the exhaust fan to spin up if either CPU or GPU are under load while the front fans still primarily serve the components closest to them. Other scenarios might include a water cooled CPU where the the VRMs might be at risk of overheating since there is no incidental airflow from the CPU cooler. It might also be a good idea to set up all case fans to spin at max speed if any component in the system reaches a critical threshold.

Why this probably isn't the right place to solve this I took a quick look at the fan control script and to my surprise its actually pretty simple. While something like I'm proposing could most likely be build into that, one has to ask if lm-sensors would be the right place to do it. I believe this would exceed of what should be done in a bash script. And anything that's more than a simple bash script should probably be its own thing instead of bloating lm-sensors.

But since I wont start a new project over this and wouldnt expect any one else to do it, It'll probably just have to stay like that for the foreseeable future. Realistically speaking we probably all have more important things to do.

zdzichu commented 3 years ago

I think fancontrol should stay simple. It works fine in basic scenarios, and provides a good starting point if you need something more advanced. Using fancontrol as an inspiration I was able to whip python script using PID controller and cooling fluid temperature as an input. If you don't want to code by yourself, there are multitude of ready solutions, like this one: https://github.com/KostyaEsmukov/afancontrol

dining-philosopher commented 3 years ago

Hello!

I wrote a script to smoothen multiple temperatures over some time and write it into a file so fancontrol can read it as temperature input:

#!/usr/bin/python3

import time, os

# temperature smoothener for fancontrol

dt = 0.3    # time interval between measurement points
points = 10 # smoothing decay time in points

sensors = ["/sys/class/hwmon/hwmon2/temp3_input",
           "/sys/class/hwmon/hwmon2/temp5_input",
           "/sys/class/hwmon/hwmon2/temp7_input",
           "/sys/class/hwmon/hwmon2/temp9_input"]

outfile = os.path.expanduser("/etc/smoothtemp.txt")

if __name__ == "__main__":
    temp = int(open(sensors[0]).read())
    k = 1. / points
    K = 1 - k
    k = k / len(sensors)
    print(K, k)
    if not os.path.exists(outfile):
        open(outfile, "w").close()
    myfile = open(outfile,'r+')
    while True:
        time.sleep(dt)
        t = 0
        for s in sensors:
            t += int(open(s).read())
        temp = temp * K + t * k
        myfile.seek(0)
        myfile.write(str(int(temp)) + "\n\n")
        myfile.truncate()

Installation:

  1. Copy it to /usr/bin/smoothtemp.py 1.1 Change sensors to match your system
  2. chmod +x /usr/bin/smoothtemp.py
  3. Make it run at the system startup, e. g. with systemd: 3.1 Create /etc/systemd/system/smoothtemp.service:
    
    [Unit]
    Description=temperature smoothener for fancontrol

[Service] ExecStart=/usr/bin/smoothtemp.py Restart=always RestartSec=1s

[Install] WantedBy=fancontrol.service


3.2 sudo systemctl enable smoothtemp.service
3.3 sudo systemctl start smoothtemp.service
4. Make sure it does what you want: watch -n 0.3 cat /etc/smoothtemp.txt
5. Set FCTEMPS=hwmon1/pwm2=/etc/smoothtemp.txt (or some other hwmon/pwm) in /etc/fancontrol
6. sudo systemctl restart fancontrol.service
7. ????
8. Profit!

It simply averages several temperatures into one number, but it should be easy to implement other functions or generate more than one temperature file.

I had not tried to reboot my system with these settings yet, so it may not work as intended on reboot. :(
Stonyx commented 2 years ago

Another use case where this functionality would be very helpful is now that the drivetemp kernel module exists that shows hard drive temperatures a lot of people wish they could control one or two fans based on the warmest hard drive out of many that those one or two fans are cooling.

Gazer75 commented 2 years ago

I would love to see a way to use multiple sensors and use the highest one to determine fan speed. My rear exhaust fan would love this as it should spin based on the higher of CPU or GPU.

Used to have several of my fans controlled this way in AI Suite 3, but after I got an MSI card I that program will not read GPU temps.

Stonyx commented 2 years ago

I would love to see a way to use multiple sensors and use the highest one to determine fan speed. My rear exhaust fan would love this as it should spin based on the higher of CPU or GPU.

Used to have several of my fans controlled this way in AI Suite 3, but after I got an MSI card I that program will not read GPU temps.

I made some minor changes to the fancontrol script to do exactly what you're looking for. You can find the changed file at https://github.com/Stonyx/lm-sensors/blob/master/prog/pwm/fancontrol (you can view the changes made at https://github.com/Stonyx/lm-sensors/commit/45edb41c287e3e39cff1d2ab76f08f3f4833bdd1). However, this has not been tested yet, at all. If you'd be willing to give this a test run that would be great. You specify the additional temperature sensors to use by editing the fancontrol configuration file and adding the extra sensors as a comma separated list to the existing sensor being used for a fan.

Gazer75 commented 2 years ago

I actually just added a "Mix" custom sensor where I add both GPU and CPU then select the Max function. Didn't know about that one when posting before.

Using this as the source for my Graph fan curve used by the case fans works perfectly.

Stonyx commented 2 years ago

I actually just added a "Mix" custom sensor where I add both GPU and CPU then select the Max function. Didn't know about that one when posting before.

Using this as the source for my Graph fan curve used by the case fans works perfectly.

Do you have more information on how this custom sensor was setup? Sounds like an interesting solution.

Gazer75 commented 2 years ago

image

As I said above, just hit the + and add the custom sensor then add in what sources you want and set it to use the max temp. Whatever temp is higher will be the output. Use this one as a source for the fan curves.

haudiweg commented 2 years ago

I think it woold be useful to have the feature

My fans stop spinning if its not hot

But i Woold like to use my multiple Thermal sensors on my mainboard and sensors on my nvme drives to controll my front and back fans

If i use the gpu or cpu mutch i woold like that my fans start spinning more (so higher idle case temp and lower activ case temp)

bilogic commented 8 months ago

I found myself also needing 2 temperatures to control 1 fan, they are 2 NVMe sticks in the same area of the motherboard.

Personally, the root issue seems to be in the very limited structure of /etc/fancontrol and not about increasing the complexity of the software. I mean, is if tempA or tempB > XX, then increase fan speed that complex?