Advertisement
Guest User

sunxi-temp-daemon-extended.sh

a guest
Nov 25th, 2015
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 14.78 KB | None | 0 0
  1. #!/bin/bash
  2. # write PID to pidfile, ensure deletion
  3. echo $$ >"${1}"
  4. trap "rm \"${1}\" ; exit 0" 0 1 2 3 15
  5. # set -x
  6. # exec 2>>/var/log/sunxi-temp.log
  7. #
  8. # A20/AXP209 SoC/HDD/PMU temperature daemon. Writes the current temperatures
  9. # to /tmp/soctemp, /tmp/pmutemp and /tmp/disktemp (since we're experiencing
  10. # always timeouts under heavy load when trying to get the temperatures
  11. # directly from within RPi-Monitor. All temperature values in °C were written
  12. # to the temp files multiplied with 10 to get 1 decimal place in RPi-Monitor.
  13. #
  14. # Please keep in mind that the values you get this way may be inaccurate (that
  15. # applies especially to the SoC's temperature)
  16. #
  17. # Copyright 2015 - Thomas Kaiser - http://kaiser-edv.de/
  18. #
  19. # This program is free software: you can redistribute it and/or modify
  20. # it under the terms of the GNU General Public License as published by
  21. # the Free Software Foundation, either version 3 of the License, or
  22. # (at your option) any later version.
  23. #
  24. # This program is distributed in the hope that it will be useful,
  25. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27. # GNU General Public License for more details.
  28. #
  29. # You should have received a copy of the GNU General Public License
  30. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  31.  
  32. SoCTempAdjustment=1447  # default for A20
  33. CheckInterval=7.5       # time in seconds between two checks
  34. DiskCheckInterval=60    # time in seconds between disk checks
  35. CheckAllDisks=FALSE     # if set to anything else than FALSE you've to adjust
  36.                         # your data collection settings: both name and regexp. And
  37.                         # display/graph settings should also match the count of
  38.                         # disks since the values for all found disks will be written
  39.                         # space delimited to the temp file. With 4 disks you might
  40.                         # use
  41.                         #
  42.                         # dynamic.12.name=hddtemp1,hddtemp2,hddtemp3,hddtemp4
  43.                         # dynamic.12.source=/tmp/disktemp
  44.                         # dynamic.12.regexp=^(\S+)\s(\S+)\s(\S+)\s(\S+)
  45.                         #
  46.                         # And please keep in mind that disk enumeration might not
  47.                         # be persistent across reboots so become familiar with
  48.                         # udev rules, access disks by UUID or use /dev/disk/by-id/
  49.                         # 'blkid' and 'udevadm info --query=property --name=/dev/sda'
  50.                         # are your friends and help you to get the idea.
  51.  
  52. CpuStatCheckInterval=20 # define in which interval CPU statistics should be queried
  53.                        
  54. FanCheckInterval=120    # if this variable is set then every ${FanCheckInterval} secs
  55.                         # the PMU's temperature will be checked (deg celsius * 1000).
  56. FanTempError=55000      # If it exceeds ${FanTempError} then the fan will switch on.
  57. FanTempWarn=53000       # Same when exceeding ${FanTempWarn} while CPU utilisation is
  58.                         # above 60%
  59. FanGPIO=7               # Define the GPIO pin that will trigger fan operation
  60.  
  61. TempCheckInterval=180   # In case you want to query external weather stations via HTTP
  62.                         # define an interval here and adjust the GetExternalTemp function
  63.  
  64.  
  65. # initialize variables we need later
  66. export PATH=/usr/local/bin:/usr/bin:/bin:
  67. unset LANG
  68. LastDiskCheck=0
  69. LastFanCheck=0
  70. LastTempCheck=0
  71. LastUserStat=0
  72. LastNiceStat=0
  73. LastSystemStat=0
  74. LastIdleStat=0
  75. LastIOWaitStat=0
  76. LastIrqStat=0
  77. LastSoftIrqStat=0
  78. LastCpuStatCheck=0
  79.  
  80. Main() {
  81.     # Ensure that we're running as root since otherwise querying SATA/USB disks won't work
  82.     if [ "$(id -u)" != "0" ]; then
  83.         echo "This script must be run as root" >&2
  84.         exit 1
  85.     fi
  86.    
  87.     # ensure we're writing to files instead of symlinks
  88.     CreateTempDir
  89.    
  90.     # check whether we've to control a fan
  91.     if [ "X${FanCheckInterval}" != "X" ]; then
  92.         # initialise GPIO pin to be ready to trigger the fan
  93.         echo ${FanGPIO} >/sys/class/gpio/export
  94.         echo "out" >/sys/class/gpio/gpio${FanGPIO}/direction
  95.     fi
  96.    
  97.     while true ; do
  98.         # enclosures's internal temperature/humidity
  99.         # somewhat inaccurate since we dropped a pullup resistor and sometimes the values
  100.         # are out of range. We fix this with range checks
  101.  
  102.         EncTemp=$(tail -n 40 /var/log/enclosure.log | grep "^Humidity" | tail -n3 | awk -F" " '{ total += $7*100; count++ } END { print total/count }' | cut -f1 -d.)
  103.         EncHumidity=$(tail -n 40 /var/log/enclosure.log | grep "^Humidity" | tail -n3 | awk -F" " '{ total += $3*100; count++ } END { print total/count }' | cut -f1 -d.)
  104.  
  105.         if [ ${LastFanCheck} -eq 0 ]; then
  106.             # first run -- we trust the values
  107.             LastEncTemp=${EncTemp}
  108.             echo ${EncTemp} >/tmp/enctemp
  109.             LastEncHumidity=${EncHumidity}
  110.             echo ${EncHumidity} >/tmp/enchumid
  111.         else
  112.             if [ ${EncTemp} -lt $(( ${LastEncTemp} - 4000 )) -o ${EncTemp} -gt $(( ${LastEncTemp} + 4000 )) ]; then
  113.                 echo ${LastEncTemp} >/tmp/enctemp
  114.             else  
  115.                 LastEncTemp=$(SanitizeValue ${EncTemp} ${LastEncTemp} | tee /tmp/enctemp)
  116.             fi
  117.             if [ ${EncHumidity} -lt $(( ${LastEncHumidity} - 4000 )) -o ${EncHumidity} -gt $(( ${LastEncHumidity} + 4000 )) ]; then
  118.                 echo ${LastEncHumidity} >/tmp/enchumid
  119.             else
  120.                 LastEncHumidity=$(SanitizeValue ${EncHumidity} ${LastEncHumidity} | tee /tmp/enchumid)
  121.             fi
  122.         fi
  123.  
  124.         # check disk temperature(s). We execute this only every ${DiskCheckInterval} since
  125.         # it's a bit costly (S.M.A.R.T. queries).
  126.        
  127.         TimeNow=$(( $(date "+%s") / ${DiskCheckInterval} ))
  128.         if [[ ${TimeNow} -gt ${LastDiskCheck} ]]; then
  129.             # time for a disk check. If ${CheckAllDisks} is FALSE and /dev/sda exists we
  130.             # only query this device otherwise all available (might be none)
  131.             CheckDisks
  132.             # update check timestamp
  133.             LastDiskCheck=${TimeNow}
  134.         fi
  135.  
  136.         # External temperature from weather stations
  137.         TimeNow=$(( $(date "+%s") / ${TempCheckInterval} ))
  138.         if [[ ${TimeNow} -gt ${LastTempCheck} ]]; then
  139.             # read in external temp values from 2 different web sources
  140.             ExternalTemp=$(GetExternalTemp)
  141.             LastExternalTemp=$(SanitizeValue ${ExternalTemp} ${LastExternalTemp} | tee /tmp/externaltemp)
  142.             LastTempCheck=${TimeNow}
  143.         fi
  144.        
  145.         # cpustat
  146.         TimeNow=$(( $(date "+%s") / ${CpuStatCheckInterval} ))
  147.         if [[ ${TimeNow} -gt ${LastCpuStatCheck} ]]; then
  148.             ProcessStats
  149.             LastCpuStatCheck=${TimeNow}
  150.         fi
  151.        
  152.         # Soc and PMU temp -- depends on the kernel we're running
  153.         case $(uname -r) in
  154.             3.4.*)
  155.                 if [ -x /usr/share/rpimonitor/scripts/sunxi_tp_temp ]; then
  156.                     SoCTemp=$(/usr/share/rpimonitor/scripts/sunxi_tp_temp ${SoCTempAdjustment} | awk '{printf ("%0.0f",$1*1000); }')
  157.                 fi
  158.                 read PMUTemp </sys/devices/platform/sunxi-i2c.0/i2c-0/0-0034/temp1_input
  159.                 ;;
  160.             4.*)
  161.                 # mainline kernel 4.0 or above, SoC temp should be available
  162.                 read SoCTemp </sys/class/thermal/thermal_zone0/temp
  163.         esac
  164.        
  165.         # check whether PMU value could be read before
  166.         if [ "X${PMUTemp}" = "X" ]; then
  167.             # Maybe the patches from http://sunxi.montjoie.ovh are applied and lm-sensors installed
  168.             PMUTemp=$(sensors | awk -F" " '/CHIP: / {printf ("%0.0f",$2*1000); }')
  169.         fi
  170.         LastSocTemp=$(SanitizeValue ${SoCTemp} ${LastSocTemp} | tee /tmp/soctemp)
  171.         LastPMUTemp=$(SanitizeValue ${PMUTemp} ${LastPMUTemp} | tee /tmp/pmutemp)
  172.  
  173.         # fan check
  174.         TimeNow=$(( $(date "+%s") / ${FanCheckInterval} ))
  175.         # Load1Min=$(awk -F" " '{print $1}' < /proc/loadavg | cut -d. -f1)
  176.         # Load5Min=$(awk -F" " '{print $2}' < /proc/loadavg | cut -d. -f1)
  177.         CPUTotal=$(cut -d" " -f1 </tmp/cpustat)
  178.         TheMinute="$(date "+%M")"
  179.         case ${TheMinute} in
  180.             59|00|01)
  181.                 TempTreshold=${FanTempWarn}
  182.                 ;;
  183.             *)
  184.                 TempTreshold=${FanTempError}
  185.                 ;;
  186.         esac
  187.         if [[ ${TimeNow} -gt ${LastFanCheck} ]]; then
  188.             if [ ${LastPMUTemp} -ge ${TempTreshold} ]; then
  189.                 echo 1 >/sys/class/gpio/gpio${FanGPIO}/value
  190.             elif [ ${LastPMUTemp} -ge ${FanTempWarn} -a ${CPUTotal} -ge 60 ]; then
  191.                 echo 1 >/sys/class/gpio/gpio${FanGPIO}/value
  192.             else
  193.                 echo 0 >/sys/class/gpio/gpio${FanGPIO}/value
  194.             fi
  195.             LastFanCheck=${TimeNow}
  196.         fi
  197.         sleep ${CheckInterval}
  198.     done
  199. } # Main
  200.  
  201. CreateTempDir() {
  202.     # create a safe temporary dir with the three files therein and symlinks to /tmp/
  203.     MyTempDir=$(mktemp -d /tmp/rpimonitor.XXXXXX)
  204.     if [ ! -d "${MyTempDir}" ]; then
  205.         MyTempDir=/tmp/rpimonitor.$RANDOM.$RANDOM.$RANDOM.$$
  206.         (umask 077 && mkdir ${MyTempDir}) || (echo "Failed to create temp dir. Aborting" >&2 ; exit 1)
  207.     fi
  208.     for file in cpustat externaltemp enchumid enctemp ambienttemp soctemp disktemp pmutemp camera1temp camera2temp camera3temp camera4temp camera5temp ; do
  209.         echo -n "0" > "${MyTempDir}/${file}"
  210.         chmod 644 "${MyTempDir}/${file}"
  211.         ln -f -s ${MyTempDir}/${file} /tmp/${file}
  212.     done
  213.     chmod 711 "${MyTempDir}"
  214. } #CreateTempFiles
  215.  
  216. CheckDisks() {
  217.     # We check either /dev/sda or all available block devices -- see above for
  218.     # contents/consequences of $CheckAllDisks
  219.     if [ "X${CheckAllDisks}" = "XFALSE" -a -L /sys/block/sda ]; then
  220.         DiskTemp=$(GetDiskTemp /dev/sda)
  221.         LastDiskTemp=$(SanitizeValue ${DiskTemp} ${LastDiskTemp} | tee /tmp/disktemp)
  222.     else
  223.         DiskTemp=""
  224.         for diskdevice in /sys/block/sd* ; do
  225.             RawDiskTemp=$(GetDiskTemp /dev/${diskdevice##*/})
  226.             DiskTemp="${DiskTemp}$(SanitizeValue ${RawDiskTemp}) "
  227.         done
  228.         if [ "X${DiskTemp}" = "X " ]; then
  229.             echo -n "0" >/tmp/disktemp
  230.         else
  231.             echo "${DiskTemp}" >/tmp/disktemp
  232.         fi
  233.     fi
  234. } # CheckDisks
  235.  
  236. GetDiskTemp() {
  237.     # get disk temperate using hddtemp (doesn't wake up sleeping disks and knows how to deal
  238.     # with different disks due to an included database with known disk models).
  239.    
  240.     RawTemp=$(/usr/sbin/hddtemp -n ${1} 2>/dev/null)
  241.     if [ "X${RawTemp}" = "X" ]; then
  242.         # drive is sleeping, we take the enclosure's internal temp + 4°C
  243.         read RawTemp </tmp/enctemp
  244.         echo ${RawTemp} | awk '{printf ("%0.0f",$1+4000); }'
  245.     else
  246.         echo ${RawTemp} | awk '{printf ("%0.0f",$1*1000); }'
  247.     fi
  248.    
  249.     # The commented smartctl call below is meant as an alternative and an example for USB
  250.     # disks in external enclosures that are able to answer S.M.A.R.T. queries since they're
  251.     # SAT capable:
  252.     #
  253.     # /usr/sbin/smartctl -d sat -a ${1} | awk -F" " '/Temperature_Cel/ {printf ("%0.0f",$10*10); }'
  254.     #
  255.     # You should be aware that not every enclosure supports that and that some USB-to-SATA
  256.     # bridges require different parameters (eg. '-d usbjmicron' -- have a close look at
  257.     # https://www.smartmontools.org/wiki/Supported_USB-Devices and test with smartctl to
  258.     # get the correct value of the correct attribute).
  259.     #
  260.     # You should also be aware that a query by smartctl always wakes up sleeping disks. So
  261.     # in case you want to query an external USB disk only if it's neither standby nor sleeping
  262.     # and in case the enclosure is SAT capable think about prefixing the smartctl call with
  263.     # something like:
  264.     #
  265.     # /sbin/hdparm -C ${1} | egrep -q "standby|sleeping" || /usr/sbin/smartctl ...
  266.     #
  267.     # In case you try to query multiple disks you might end up with something like
  268.     #
  269.     # case ${1} in
  270.     #     /dev/sda) /usr/sbin/hddtemp -n ${1} ... ;;
  271.     #     /dev/sdb) /usr/sbin/smartctl -d usbprolific -a ${1} ... ;;
  272.     #     /dev/sdc) /sbin/hdparm -C ${1} | egrep -q "standby|sleeping" || /usr/sbin/smartctl -d sat ... ;;
  273.     # esac
  274. } # GetDiskTemp
  275.  
  276. SanitizeValue() {
  277.     # keep thermal values in the range of 0°C-100°C since sometimes the values are massively out
  278.     # of range and then your graphs suffer from this. If a second argument is supplied then create
  279.     # an average value to smooth graphs (useful for PMU and SoC)
  280.     if [[ ${1} -lt 0 ]]; then
  281.         echo -n 0
  282.     elif [[ ${1} -ge 100000 ]]; then
  283.         echo -n ${1}
  284.     else
  285.         if [[ "X$2" = "X" ]]; then
  286.             echo -n ${1}
  287.         else
  288.             echo -n $(( ( $1 + $2 * 5 ) / 6 ))
  289.         fi
  290.     fi
  291. } # SanitizeValue
  292.  
  293. SanitizeValueFinegrade() {
  294.     # keep thermal values in the range of 0°C-100°C since sometimes the values are massively out
  295.     # of range and then your graphs suffer from this. If a second argument is supplied then create
  296.     # an average value to smooth graphs (useful for enclosure's temperature and humidity -- they
  297.     # are reported as integers and by processing them with one more decimal place we get smoother
  298.     # graphs
  299.     if [[ ${1} -lt 0 ]]; then
  300.         echo -n 0
  301.     elif [[ ${1} -gt 10000 ]]; then
  302.         echo -n 10000
  303.     else
  304.         if [[ "X$2" = "X" ]]; then
  305.             echo -n ${1}
  306.         else
  307.             echo -n $(( ( $1 + $2 * 15 ) / 16 ))
  308.         fi
  309.     fi
  310. } # SanitizeValueFinegrade
  311.  
  312. ProcessStats() {
  313.     set $(awk -F" " '/^cpu / {print $2"\t"$3"\t"$4"\t"$5"\t"$6"\t"$7"\t"$8}' </proc/stat)
  314.     UserStat=$1
  315.     NiceStat=$2
  316.     SystemStat=$3
  317.     IdleStat=$4
  318.     IOWaitStat=$5
  319.     IrqStat=$6
  320.     SoftIrqStat=$7
  321.    
  322.     UserDiff=$(( ${UserStat} - ${LastUserStat} ))
  323.     NiceDiff=$(( ${NiceStat} - ${LastNiceStat} ))
  324.     SystemDiff=$(( ${SystemStat} - ${LastSystemStat} ))
  325.     IdleDiff=$(( ${IdleStat} - ${LastIdleStat} ))
  326.     IOWaitDiff=$(( ${IOWaitStat} - ${LastIOWaitStat} ))
  327.     IrqDiff=$(( ${IrqStat} - ${LastIrqStat} ))
  328.     SoftIrqDiff=$(( ${SoftIrqStat} - ${LastSoftIrqStat} ))
  329.    
  330.     Total=$(( ${UserDiff} + ${NiceDiff} + ${SystemDiff} + ${IdleDiff} + ${IOWaitDiff} + ${IrqDiff} + ${SoftIrqDiff} ))
  331.     CPULoad=$(( ( ${Total} - ${IdleDiff} ) * 100 / ${Total} ))
  332.     UserLoad=$(( ${UserDiff} *100 / ${Total} ))
  333.     SystemLoad=$(( ${SystemDiff} *100 / ${Total} ))
  334.     NiceLoad=$(( ${NiceDiff} *100 / ${Total} ))
  335.     IOWaitLoad=$(( ${IOWaitDiff} *100 / ${Total} ))
  336.     IrqCombinedLoad=$(( ( ${IrqDiff} + ${SoftIrqDiff} ) *100 / ${Total} ))
  337.    
  338.     echo "${CPULoad} ${SystemLoad} ${UserLoad} ${NiceLoad} ${IOWaitLoad} ${IrqCombinedLoad}" >/tmp/cpustat
  339.  
  340.     LastUserStat=${UserStat}
  341.     LastNiceStat=${NiceStat}
  342.     LastSystemStat=${SystemStat}
  343.     LastIdleStat=${IdleStat}
  344.     LastIOWaitStat=${IOWaitStat}
  345.     LastIrqStat=${IrqStat}
  346.     LastSoftIrqStat=${SoftIrqStat}
  347. } # ProcessStats
  348.  
  349. GetExternalTemp() {
  350.     # function that parses meteo.physik.uni-muenchen.de and mingaweda.de
  351.     # temperature values for Munich and compares them. When values are out
  352.     # of bounds then only the other value will be returned otherwise the average
  353.     ExternalTemp1=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.meteo.physik.uni-muenchen.de/dokuwiki/doku.php?id=wetter:stadt:messung" | awk -F" " '/Lufttemperatur/ {printf ("%0.0f",$4*1000); }')
  354.     ExternalTemp2=$(/usr/bin/links -http.fake-user-agent 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12' -dump "http://www.mingaweda.de/wetterdaten/" | awk -F" " '/Ausfu:hrliche/ {printf ("%0.0f",$2*1000); }')
  355.    
  356.     if [ "X${ExternalTemp2}" = "X" ]; then
  357.         ExternalTemp2=${ExternalTemp1}
  358.     elif [ "X${ExternalTemp1}" = "X" ]; then
  359.         ExternalTemp1=${ExternalTemp2}
  360.     fi
  361.  
  362.     echo $(( ( ${ExternalTemp1} + ${ExternalTemp2} ) / 2 ))
  363. } # GetExternalTemp
  364.  
  365. Main
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement