Advertisement
danielbugs

RPI5 fan control Ubuntu (v1.01)

Nov 18th, 2023 (edited)
1,460
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.65 KB | None | 0 0
  1. from sys import exit as sysexit
  2. from os import _exit as osexit
  3. from subprocess import run as srun, PIPE
  4. from time import sleep
  5. from datetime import timedelta as td, datetime as dt
  6. from enum import Enum
  7.  
  8.  
  9. ## Use step values to activate desired FAN value
  10. STEP1 = 44
  11. STEP2 = 60
  12. STEP3 = 65
  13. STEP4 = 72
  14. DELTA_TEMP = 3
  15.  
  16. ## Change these values if you want a more/less responsive fan behavior
  17. SLEEP_TIMER = 5
  18. TICKS = 3
  19. TICK_INTERVAL = 2
  20.  
  21. ## These should no be changed
  22. DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S'
  23. fanControlFile = '/sys/class/thermal/cooling_device0/cur_state'
  24. command = f'tee -a {fanControlFile} > /dev/null'
  25.  
  26. class FanState(Enum):
  27.     OFF = 0
  28.     LOW = 1
  29.     MID = 2
  30.     HIGH = 3
  31.     MAX = 4
  32.  
  33.  
  34. def main(debug=False):
  35.     print("Running FAN control for RPI5 Ubuntu")
  36.     t0 = dt.now()
  37.     _fs = FanState
  38.  
  39.     oldSpeed = _fs.OFF
  40.     ticks = 0
  41.  
  42.     speed = _fs.MID
  43.     lastTemp = 0
  44.  
  45.     while True:
  46.         sleep(SLEEP_TIMER) # force sleep, just to reduce polling calls
  47.         t1 = dt.now()
  48.         if(t1 + td(minutes=TICKS) > t0):
  49.             t0 = t1
  50.            
  51.             tempOut = getOutput('vcgencmd measure_temp')
  52.             try:
  53.                 cels = int(tempOut.split('temp=')[1][:2])
  54.             except (IndexError, ValueError) as e:
  55.                 cels = STEP2 + 2 # force avg temp, in case of parsing error
  56.  
  57.             if STEP1 < cels < STEP2:
  58.                 speed = _fs.LOW
  59.             elif STEP2 < cels < STEP3:
  60.                 speed = _fs.MID
  61.             elif STEP3 < cels < STEP4:
  62.                 speed = _fs.HIGH
  63.             elif cels >= STEP4:
  64.                 speed = _fs.MAX
  65.  
  66.             deltaTempNeg = lastTemp - DELTA_TEMP
  67.             deltaTempPos = lastTemp + DELTA_TEMP
  68.  
  69.             if oldSpeed != speed and not(deltaTempNeg <= cels <= deltaTempPos):
  70.                 if debug:
  71.                     print(f'oldSpeed: {oldSpeed} | newSpeed: {speed}')
  72.                     print(f'{deltaTempNeg}ºC <= {cels}ºC <= {deltaTempPos}ºC')
  73.  
  74.                 print(f'{"#"*30}\n' +
  75.                     f'Updating fan speed!\t{t0.strftime(DATETIME_FORMAT)}\n' +
  76.                     f'CPU TEMP: {cels}ºC\n' +
  77.                     f'FAN speed will be set to: {speed}\n' +
  78.                     f'{"#"*30}\n')
  79.                
  80.                 _speed = -1
  81.                 try:
  82.                     _speed = speed.value
  83.                 except AttributeError:
  84.                     _speed = speed
  85.                 _command = f'echo {_speed} | sudo {command}'
  86.                 callShell(_command)
  87.                
  88.                 if debug:
  89.                     checkVal = getOutput(f'cat {fanControlFile}')
  90.                     print(f'Confirm FAN set to speed: {checkVal}')
  91.                
  92.                 # Updating values for comparison
  93.                 oldSpeed = speed
  94.                 lastTemp = cels
  95.                 ticks = 0
  96.            
  97.             # Log minor details
  98.             ticks += 1
  99.             if(ticks > TICKS * TICK_INTERVAL):
  100.                 ticks = 0
  101.                 print(f'Current Temp is: {cels}ºC\t{t0.strftime(DATETIME_FORMAT)}')
  102.    
  103.  
  104. def callShell(cmd, shell=True, debug=False):
  105.     if debug:
  106.         print(f'Calling: [{cmd}]')
  107.     return srun(f'''{cmd}''', stdout=PIPE, shell=shell)
  108.  
  109.  
  110. def getOutput(cmd, shell=True):
  111.     stdout = callShell(cmd, shell=shell).stdout
  112.  
  113.     try:
  114.         stdout = stdout.decode('utf-8')
  115.     except:
  116.         pass
  117.  
  118.     return stdout
  119.  
  120.  
  121. ## RUN SCRIPT
  122. if __name__ == '__main__':
  123.     try:
  124.         main(True)
  125.     except KeyboardInterrupt:
  126.         print('Interrupted')
  127.         try:
  128.             sysexit(130)
  129.         except SystemExit:
  130.             osexit(130)
  131.  
Advertisement
Comments
  • danielbugs
    1 year
    # text 0.29 KB | 0 0
    1. Save as python script file, and create a service to have it start at runtime.
    2.  
    3. [Unit]
    4. Description=RPi5 python fan control
    5. After=multi-user.target
    6.  
    7. [Service]
    8. Type=simple
    9. Restart=always
    10. User=root
    11. ExecStart=/usr/bin/python3 /path/to/file/<script>.py
    12.  
    13. [Install]
    14. WantedBy=multi-user.target
    15.  
Add Comment
Please, Sign In to add comment
Advertisement