Learn Some Linux Series - Script to measure and report CPU temperature by sending you emails

While I will write a tutorial in few parts on the subject of Bash Scripting, this one is a small tutorial that uses a script mostly developed by @huidbui25 . I have changed it slightly with assistance of @MichaIng and @Jappe to use on an old PC Engines APU 1d box with 16GB of mSATA SSD and 2GB of RAM. This one being passive cooled by the metal case, runs much higher temperature than my RPis running DietPi (and yes they are 28 to 38 deg C), and I am running Debian 11 on the APU boxes. But this script will also work on RPi. I have added some comments to help novices like me to better understand the scripting code. @Joulinar has been of great help and support as he does to everyone. Towards the end, you will see how in three scenarios, script actually executes and that helps in troubleshooting if you do run into some issues, including syntax. If you are windows users like me, try to use something like notepad ++ to copy and work on the script and then use nano (simplistic code editor available in RPi and most Linux distributions).

  1. First step is to write the script.
  2. Second script is to apply the script.
  3. Third step is to make this script executable with required file permissions.
  4. Fourth step is to add this script to a utility that will run this script on its own at a set schedule. This utility in Linux is crontab and is invoked by “crontab -e” without quotes of course, which will automatically run with a default code editor like nano (or in my case, when I used debian, it asked me first time to pick nano or vi, the latter being complicated for most of us, but does offer lots of flexibility, speed to the programmers). I will write separate small tutorials on nano, cron, firewalling (IPtables and UFW for natting and portforwarding etc), file handling, NoMachine for remote access, if we need to fire a browser on the small devices to control small things that may sit behind them (like an ISP router, or a wireless AP), and also on some basics of scripting as I learn myself.
#*****Full Working Script for CPU Temperature Warning and Alerts via Emails*******
#***** Credits go to original author @huidbui25
#****** https://dietpi.com/forum/t/tutorial-check-cpu-temperature-and-send-warning-mail/3845 *****
# Further modified with assistance of @Jappe and @MichaIng to work on any Linux platform and on RPi
# I am using smtp2go account for email relays and it is free or very low cost depending upong your needs.
# You should have DMA (Draganfly Mail Agent) package installed (apt install dma) which also installs sendmail, the basic utility used by DMA to send out email. 
# See details of DMA install and configuration on link above.
# **** Script > a series of commands to be executed by the interpretation by certain interpreter, for automating certain repetitive task.
# Anything preceded by # is a comment and not considered to be a command or statement to be executed.
# bash is used as a interpreter for most Linux Scripts. Shebang (#!) or sharp-bang shown in next statement is not a comment line though to some extent, but with ! behind #, OS takes it as magic bytes to refer it to bash and ignore this line itself as a script command. 
# path to bash (shell interpreter) is listed below

#!/bin/bash

## VARIABLES to be used in the Script##

# Input Temperature thresholds  here. Use integers only. And Values are in degree Celsius.
# Alarm and Warnings use separate severity mail subject and also mark the emails as important.
# tmp_unit should not be changed to F or K or R:). This variable is used for simple appending for email text.
tmp_warn="65"
tmp_alarm="78"
tmp_unit="C"

# The info needed for sending mails
# To send to multiple recipients, specify multiple, to addresses, by comma separation.
FROM_NAME="PCEng Lab"
FROM_ADDRESS="PCEng@domain.com"
TO_NAME="Lab"
TO_ADDRESS="lab@domain.com"
MAIL_FILE="/tmp/mail_tmp.txt"


## SCRIPT ##

# Statement below stores the current CPU temperature to a variable called tmp_chk
# mawk (a AWK language interpreter, AWK being last name initials of 3 engineer authors of this tool and >
# m in MAWK is first initial of author of interpreter),>
# parses the output of command listed here as first place argument (denoted by $1), > 
# using printf function by diving the command output by 1000 and with zero decimal places (0f)
# variable value assigned or computed is stored into $variable. To use variable subsequently, we then use it as $variable

tmp_chk=$(mawk '{printf("%.0f",$1/1000)}' /sys/class/thermal/thermal_zone0/temp)

# this section below is just for a test run to check emails are fired from the Script without generating conditions for Script to act.

if [ "$1" == "test" ]
# $1 equal to test here implies that when we run the script by appending first place argument as test

then
  tmp_chk="200"

# this is to continue downwards the execution of script

elif [ -z "$tmp_chk" ]

# -z is used to check if value of following variable is empty and then condition output is true, else false

then
  echo "${0##*/}: Error at reading the CPU temperature. Unknown command? No numeric value? Aborting script."
  exit 1
fi
# ${0##*/} prints the script name by removing the path name from the script file. So /usr/local/bin/temp_mon becomes temp_mon.

# Section below determines whether the current temperature is above warning and/or alarm threshold

status_warn=$(echo $tmp_chk '>=' $tmp_warn | bc -l)
status_alarm=$(echo $tmp_chk '>=' $tmp_alarm | bc -l)

# bc is important to allow arithmetic operations on decimal numbers, else bash scripts can only handle integers.

# Section below terminates script when neither of two thresholds condition occur

if [[ "$status_warn" == 0 && "$status_alarm" == 0 ]]
then
  exit 0
fi

# Generates the mail text that will be sent out

echo "From: \"$FROM_NAME\" <$FROM_ADDRESS>" > $MAIL_FILE
echo "To: \"$TO_NAME\" <$TO_ADDRESS>" >> $MAIL_FILE

if [ $status_alarm == 1 ]
then
  echo "Subject: Temperature ALARM" >> $MAIL_FILE
  echo "X-Priority: 1 (Highest)" >> $MAIL_FILE
  echo "X-MSMail-Priority: High" >> $MAIL_FILE
  echo "Importance: High" >> $MAIL_FILE
elif [ $status_warn == 1 ]
then
  echo "Subject: Temperature warning" >> $MAIL_FILE
fi

# -eq or == for comparison, but not = in  the, if, elif (else if) conditions.
 
echo "Content-type: text/plain; charset=utf-8" >> $MAIL_FILE
echo "Content-Language: en" >> $MAIL_FILE
echo "X-Auto-Response-Suppress: OOF" >> $MAIL_FILE
echo "" >> $MAIL_FILE
echo "CPU temperature is High!" >> $MAIL_FILE
echo "Current temp: $tmp_chk °$tmp_unit" >> $MAIL_FILE
if [ "$1" == "test" ]
then
  echo "" >> $MAIL_FILE
  echo "Please note:"  >> $MAIL_FILE
  echo "Script was run in *test mode* to check email delivery, this not the real CPU temperature!" >> $MAIL_FILE
fi
echo "" >> $MAIL_FILE
echo "--- " >> $MAIL_FILE
echo "Sent by ${0##*/} script" >> $MAIL_FILE
echo "" >> $MAIL_FILE

# gathers the text deposited into MAIL_FILE by above actions and sends using sendmail mail relay agent. 
cat $MAIL_FILE | sendmail -f $FROM_ADDRESS $TO_ADDRESS && logger "${0##*/}: high CPU temperature: $tmp_chk °$tmp_unit, mail sent" 

# deletes the temp file
rm $MAIL_FILE

To apply the script, we simply use the commands below:

nano /usr/local/bin/temp_mon 

(if file specified at the path does not exist, then nano creates the file. You can also append .sh to help decipher that this is a script shell file though Linux file system does not care for extension)

Before we run it, we give it execution-al rights.

chmod +x /usr/local/bin/temp_mon

and to manually run it,

bash /usr/local/bin/temp_mon

(append -x after bash to see this in action as shown below)

and to test that emails are working for you,

bash /usr/local/bin/temp_mon test

Here test is a positional parameter located at position 1 and shown in script above in a if condition statement as $1 == test.

And then you put it in cron for periodic execution as below:

crontab -e

# Checks CPU temperature every 15 minutes and sends mail if it exceeds a threshold

*/15 * * * * sudo bash /usr/local/bin/temp_mon
service cron reload 

for RPi

or

systemctl restart cron 

for debian and other Linux distros

Save by pressing Ctrl and X at the same time and then pressing Y at next step.

And before I end it, DMA package after installed, needs to be slightly configured (you can also refer to details in original author’s link at the top). basically you edit couple of files using nano, the dma.conf

nano  /etc/dma/dma.conf 
SMARTHOST mail.smtp2go.com
PORT 465

and the file auth.conf will need to have the credentials from your account set up at the mail relay provider, something like in a single line

nano  /etc/dma/auth.conf 
youraccountemail@domain.com|mail.smtp2go.com:youraccountpassword

and then save it with Ctrl-X and then Y.

Also change the file below

nano /etc/mailname, 
devicenameOrlocation@domain.com

Note with smtp2go, I can use my registered domain name to create these dummy sender emails, even though I use Office365 based email on same domain. I am sure they will not allow you to use something like PCEng@gmail.com.

----------------------------------------------------------------------------------------------------------
Script Execution Steps

`***** When all is good *****`
root@TestHost:~# bash -x /usr/local/bin/temp_mon
+ tmp_warn=60
+ tmp_alarm=75
+ tmp_unit=C
+ FROM_NAME='PCEng Lab'
+ FROM_ADDRESS=PCEng@domain.com
+ TO_NAME='Lab'
+ TO_ADDRESS=lab@domain.com
+ MAIL_FILE=/tmp/mail_tmp.txt
++ mawk '{printf("%.0f",$1/1000)}' /sys/class/thermal/thermal_zone0/temp
+ tmp_chk=58
+ '[' '' == test ']'
+ '[' -z 58 ']'
++ echo 58 '>=' 60
++ bc -l
+ status_warn=0
++ echo 58 '>=' 75
++ bc -l
+ status_alarm=0
+ [[ 0 == 0 ]]
+ [[ 0 == 0 ]]
+ exit 0

`***** When temperature is in warning zone *****`

root@MonHost:~# bash -x /usr/local/bin/temp_mon
+ tmp_warn=50
+ tmp_alarm=75
+ tmp_unit=C
+ FROM_NAME='PCEng Lab'
+ FROM_ADDRESS=PCEng@domain.com
+ TO_NAME='Lab'
+ TO_ADDRESS=lab@domain.com
+ MAIL_FILE=/tmp/mail_tmp.txt
++ mawk '{printf("%.0f",$1/1000)}' /sys/class/thermal/thermal_zone0/temp
+ tmp_chk=58
+ '[' '' == test ']'
+ '[' -z 58 ']'
++ echo 58 '>=' 50
++ bc -l
+ status_warn=1
++ echo 58 '>=' 75
++ bc -l
+ status_alarm=0
+ [[ 1 == 0 ]]
+ echo 'From: "PCEng Lab" <PCEng@domain.com>'
+ echo 'To: "Lab" <lab@domain.com>'
+ '[' 0 -eq 1 ']'
+ '[' 1 -eq 1 ']'
+ echo 'Subject: Temperature warning'
+ echo 'Content-type: text/plain; charset=utf-8'
+ echo 'Content-Language: en'
+ echo 'X-Auto-Response-Suppress: OOF'
+ echo ''
+ echo 'CPU temperature is High!'
+ echo 'Current temp: 58 °C'
+ '[' '' == test ']'
+ echo ''
+ echo '--- '
+ echo 'Sent by temp_mon script'
+ echo ''
+ cat /tmp/mail_tmp.txt
+ sendmail -f PCEng@domain.com lab@domain.com
+ logger 'temp_mon: high CPU temperature: 58 °C, mail sent'
+ rm /tmp/mail_tmp.txt

***** When temperature is in alarming zone *****

root@TestHost:~# bash -x /usr/local/bin/temp_mon

+ tmp_warn=50
+ tmp_alarm=55
+ tmp_unit=C
+ FROM_NAME='PCEng Lab'
+ FROM_ADDRESS=PCEng@domain.com
+ TO_NAME='Lab'
+ TO_ADDRESS=lab@domain.com
+ MAIL_FILE=/tmp/mail_tmp.txt
++ mawk '{printf("%.0f",$1/1000)}' /sys/class/thermal/thermal_zone0/temp
+ tmp_chk=58
+ '[' '' == test ']'
+ '[' -z 58 ']'
++ echo 58 '>=' 50
++ bc -l
+ status_warn=1
++ echo 58 '>=' 55
++ bc -l
+ status_alarm=1
+ [[ 1 == 0 ]]
+ echo 'From: "PCEng Lab" <PCEng@domain.com>'
+ echo 'To: "Lab" <lab@domain.com>'
+ '[' 1 -eq 1 ']'
+ echo 'Subject: Temperature ALARM'
+ echo 'X-Priority: 1 (Highest)'
+ echo 'X-MSMail-Priority: High'
+ echo 'Importance: High'
+ echo 'Content-type: text/plain; charset=utf-8'
+ echo 'Content-Language: en'
+ echo 'X-Auto-Response-Suppress: OOF'
+ echo ''
+ echo 'CPU temperature is High!'
+ echo 'Current temp: 58 °C'
+ '[' '' == test ']'
+ echo ''
+ echo '--- '
+ echo 'Sent by temp_mon script'
+ echo ''
+ cat /tmp/mail_tmp.txt
+ sendmail -f PCEng@domain.com lab@domain.com
+ logger 'temp_mon: high CPU temperature: 58 °C, mail sent'
+ rm /tmp/mail_tmp.txt
2 Likes