Nueva versión 8
- Con o sin GUI. Activado por defecto, se puede desactivar mediante una variable en el script, mediante el parámetro -g o pulsando “No” en el primer diálogo. Se desactiva automáticamente si no detecta ningún escritorio, leyendo la variable $XDG_CURRENT_DESKTOP.
- Autoinstalación. Si no detecta el script secundario, inicia el script en modo de instalación. Pide permisos mediante pkexec si el GUI está activado o mediante sudo por terminal si no lo está. Crea el script secundario en /usr/bin/setfreq.sh, le asigna propietario root:root y permisos 755, y añade a /etc/sudoers una línea para que deba ejecutarse con sudo pero no pida contraseña. Ya no hace falta usar dos scripts: el script secundario está contenido en el principal, como una cadena de texto.
- El tamaño del archivo de log se ha limitado a 250 líneas. Se comprueba al final de cada bucle. Cuando se rebasa ese límite, se eliminan las líneas más antiguas.
- Pequeñas correcciones y optimizaciones.
Falta:
- Añadir idiomas.
- El tamaño del log debería ser configurable. En fin, eso es secundario, ya lo haré.
- Mejorar el formato del log. Ahora mismo no es todo lo legible que me gustaría.
He aquí el monstruo:
temperatura.sh
#!/bin/bash
# -*- ENCODING: UTF-8 -*-
# Default variables. You can change it to run the script easily.
delay=0
seconds=0
t_limit=85
t_normal=75
logfile="/dev/null" # <- File used as log.
notif="yes"
gui=true
# Special argument: if /usr/bin/setfreq.sh is not present, it creates them and stablishes permissions:
if [ "$1" == "install" ]; then
echo -e '#!/bin/bash\n# -*- ENCODING: UTF-8 -*-\n\n# This script MUST be launched by root\n\n# Setting the governor to "userspace":\nif [ "$1" == "userspace" ]; then\n echo userspace | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor &> /dev/null\n test -n "`grep -v "userspace" /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor`" && echo "Failed swithing to the userspace governor! Might not be supported or compiled in." && exit 1\n exit 0\nfi\n\n# Changing the max speed:\necho "$1" | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed > /dev/null\nexit 0' > /usr/bin/setfreq.sh
chown root:root /usr/bin/setfreq.sh
chmod 755 /usr/bin/setfreq.sh
# This test if sudoers is configured, and configure it if not:
if [ $(grep -c 'ALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' /etc/sudoers) -eq 0 ]; then
echo -e '\n# Users cat execude this with sudo without password:\nALL ALL=(ALL) NOPASSWD: /usr/bin/setfreq.sh' >> /etc/sudoers
fi
exit
fi
# Internal variables. Please, do not change.
t_cur=0
t_max_total=0
# Variables assigned by parameters:
if [[ $1 ]]; then
if [ $1 == "-h" ] || [ $1 == "--help" ]; then
echo -e "This script monitorize the temperature of the CPU, decreases the maximum frequency when temp is too high, and increase than when temp is low enough, and can create a log with its actions, temperatures, frequencies and date and time."
echo -e "List of valid parameters:"
echo -e "-d <seconds> \t Delay before executing the sript."
echo -e "-t <seconds> \t Time in seconds for check free memory. If 0, the script never stops."
echo -e "-l <ºC> \t Maximum dessired temperature."
echo -e "-r <ºC> \t Minimum temperature to restore maximum performance."
echo -e "-f <file> \t File used as log."
echo -e "-n <yes | no> \t Enable or disable desktop notifiacions."
echo -e "-g \t Disable GUI dialogs."
echo -e "\nExample: Limit frequency when the temperature is 85ºC, restore it when temperature is below 75ºC and show desktop notifications:\n\n ./temperature.sh -l 85 -r 75 -n yes"
echo -e "\nExample: Limit frequency when the temperature is 70ºC, restore it when temperature is below 50ºC, wait 30 seconds, run the script for 5 minutes (300 seconds), disable GUI dialogs and log the changes in <HOME>/temper.txt:\n\n ./tepmerature.sh -l 70 -r 50 -d 30 -t 300 -g -f ~/temper.txt"
exit
fi
# Reading arguments. Add "####" for priority over GUI diaglogs; it will be removed after that.
while getopts d:t:l:r:f:n:g flag
do
case "${flag}" in
d) delay=${OPTARG}"####";;
t) seconds=${OPTARG}"####";;
l) t_limit=${OPTARG}"####";;
r) t_normal=${OPTARG}"####";;
f) logfile=${OPTARG}"####";;
n) notif=${OPTARG}"####";;
g) gui=false;;
*) echo -e "Valid arguments: -d <seconds> -t <seconds> -l <Cº> -n <Cº> -f <file> -n <yes | no>\nUse -h for help."
exit;;
esac
done
fi
# Active or disable notifications.
# Maximum priority are:
# 1º Must exist a desktop.
# 2º Argument from console ( -g ).
# 3º Default variable at the beggining of the script ( notif= ).
# 4º If not disabled yet, show a dialog to acivate or not.
if [ -z "$XDG_CURRENT_DESKTOP" ]; then
# There are no desktop.
notif="no"
gui=false
elif [ $gui == true ]; then
# There are desktop and default gui variable is true
zenity --question --text "¿Configuración gráfica?" --no-wrap --ok-label "Vale" --cancel-label "No" 2>/dev/null
if [ $? == 0 ]; then
gui=true
else
gui=false
fi
fi
# AUTOINSTALL
# Test if the superuser part of this script is installed. If not, it launches the script on installation mode.
if ! [ -f /usr/bin/setfreq.sh ]; then
if [ -z "$XDG_CURRENT_DESKTOP" ] || [ $gui == false ]; then
# There are no desktop, or GUI disabled.
read -r -p "Script /usr/bin/setfreq not found. ¿Install? (y/n)" a
if [ "$a" == "y" ]; then
sudo ./temperatura.sh install
else
echo "Exiting..."
exit
fi
else
# GUI enabled.
zenity --question --text "/usr/bin/setfreq not found. ¿Install?\nIt needs root access." --no-wrap --ok-label "Install" --cancel-label "Cancel" 2>/dev/null
if [ $? == 0 ]; then
pkexec ./temperatura.sh install
else
exit
fi
fi
fi
# GUI: Setting variables not stablished by parameters:
if [ $gui == true ]; then
if [[ $delay != *"####"* ]]; then
delay=$(zenity --entry --title "Delay (s): " --text "Time waiting for start the srcipt: " --entry-text="$delay") 2>/dev/null
fi
if [[ $seconds != *"####"* ]]; then
seconds=$(zenity --entry --title "Time (s): " --text "Time running the srcipt: " --entry-text="$seconds") 2>/dev/null
fi
if [[ $t_limit != *"####"* ]]; then
t_limit=$(zenity --entry --title "Max temperature (ºC): " --text "Temperature to start reducing frequency: " --entry-text="$t_limit") 2>/dev/null
fi
if [[ $t_normal != *"####"* ]]; then
t_normal=$(zenity --entry --title "Normal temperature (ºC): " --text "Temperature to start increasing frequency: " --entry-text="$t_normal") 2>/dev/null
fi
if [[ $notif != *"####"* ]]; then
zenity --question --title "Notifiactions" --text "Do tou want desktop notifications?" --no-wrap --ok-label "Yes" --cancel-label "No" 2>/dev/null
if [ $? == 0 ]; then
notif="yes"
else
notif="no"
fi
fi
if [[ $logfile != *"####"* ]]; then
wlf=$(zenity --question --title "Log file" --text "Select a file or create a new one?" --switch --extra-button "Select" --extra-button "Create" --extra-button "None") 2>/dev/null
if [ $wlf = "Select" ]; then
logfile_gui=$(zenity --file-selection --text "Location of new file: " --filename "${HOME}/") 2>/dev/null
if [ $? == 0 ]; then
logfile=$logfile_gui
fi
elif [ $wlf = "Create" ]; then
logfile_gui=$(zenity --entry --title "Log file" --text "Write the route: " --entry-text="${HOME}/temp_log.txt") 2>/dev/null
if [ $? == 0 ]; then
logfile=$logfile_gui
fi
else
logfile=/dev/null
fi
fi
fi
# Cleaning variables:
notif=${notif%"####"}
delay=${delay%"####"}
seconds=${seconds%"####"}
t_limit=${t_limit%"####"}
t_normal=${t_normal%"####"}
logfile=${logfile%"####"}
# If used character ~ to use the /home/user folder, change it to ${HOME} to use in redirections:
logfile=${logfile//\~/"${HOME}"}
echo -e "Delay: $delay\nseconds: $seconds\nt_limit: $t_limit\nt_normal: $t_normal\nlogfile: $logfile\nnotif: $notif\ngui: $gui" ############### FOR DEBUGGIN ############
# For unlimited execution:
if [ $seconds == 0 ]; then
infinite=1
seconds=1000
else
infinite=0
fi
echo -e "\n"$(date)"\n___________________ Nueva sesión ___________________" >> "$logfile"
sleep $delay
# Setting the governor to "userspace":
sudo /usr/bin/setfreq.sh userspace
# Obtain current, max and min frequency:
f_min0=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq 2>/dev/null`
f_max0=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq 2>/dev/null`
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
f_newlimit=$f_max0
[ $notif == "yes" ] && zenity --notification --text="-Frecuencia máxima: $f_newlimit" 2>/dev/null
# Setting the current temperature to maximum:
sudo /usr/bin/setfreq.sh $f_newlimit
# ----------------------- Principal loop -----------------------
until [ $seconds -lt 1 ]; do
# Read the highest temperature from all sensors:
t_cur=$(sensors | grep °C | awk -F '+' '{print $2}' | awk -F '°C' '{print $1}' | awk -F '.' '{print $1}' | sort -nr | head -n1)
# Decrease frequency when temperature is too high
if [ $t_cur -gt $t_limit ] && [ $f_newlimit -gt $f_min0 ]; then
# Decease frequency in proportion to excesive temperature
diff=$((t_cur - t_limit))
step=$((diff * 50000))
step=$(( step > 400000 ? 400000 : step ))
f_newlimit=$((f_newlimit - step))
if [ $f_newlimit -lt $f_min0 ]; then
f_newlimit=$f_min0
fi
sudo /usr/bin/setfreq.sh $f_newlimit
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
echo -e "\n"$(date)"\n-> Bajando frecuencia máxima: "$f_newlimit"\nFrecuencia acual: "$f_cur0"\n Temperatura actual: "$t_cur >> $logfile
[ $notif == "yes" ] && zenity --notification --text="-> Bajando frecuencia máxima: $f_newlimit" 2>/dev/null
sleep 4
((seconds-=4))
# Icrease frequency when temperature is acceptable
elif [ $t_cur -lt $t_normal ] && [ $f_newlimit -lt $f_max0 ]; then
f_newlimit=$((f_newlimit + 200000))
if [ $f_newlimit -gt $f_max0 ]; then
f_newlimit=$f_max0
fi
sudo /usr/bin/setfreq.sh $f_newlimit
echo -e "\n"$(date)"\n-> Subiendo frecuencia máxima: "$f_newlimit"\nFrecuencia acual: "$f_cur0"\n Temperatura actual: "$t_cur >> $logfile
[ $notif == "yes" ] && zenity --notification --text="-> Subiendo frecuencia máxima: $f_newlimit" 2>/dev/null
f_cur0=`cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq 2>/dev/null`
sleep 4
((seconds-=4))
fi
if [ $t_cur -gt $t_max_total ]; then
t_max_total=$t_cur
echo -e "\nTemperatura máxima del intervalo: "$t_max_total >> $logfile
fi
sleep 1
((seconds--))
if [[ $infinite -eq 1 ]]; then
seconds=1000
fi
# Limits log file size
if [ $(wc -l < $logfile) -gt 250 ]; then
templog=$(tail -n 250 $logfile)
cat <<<$templog > $logfile
fi
done