Script to check the power status, and shutdown if battery is low!


Recommended Posts

If anyone is interested, I've created a shell script that can be run with cron to check A/C and battery status, and do a graceful shutdown when a battery threshold is met.  It also logs power outages, battery drain when off A/C, and when it posts a shutdown (if any).  This is a simple script, nothing fancy, but works for me.  It has a granularity of one minute (cron is limited to one minute intervals), but I've been able to keep the system up on heavy load for 4-5 minutes before the script generates a shutdown on low battery.

 

The script is generous -- it waits for 916mV or less before a shut-down.  This value was provided by the KOBOL team on their Wiki as the recommended shutdown threshold for the battery, but can be changed via the script.  You can comment out any file-logging lines, or change the file location, also from within the script.  I've heavily commented it, should be pretty easy to follow.

 

Copy the script below into a file named whatever you choose, place it where you want to run it, and cron it to get it going.  It should only create disk writes when the power is out or when shutting down from battery drain on no A/C (a few lines once per minute), and will create no disk writes  if you comment out the logging.

 

Spoiler

#!/bin/bash

# Basic calls for power stats and variables
BATTINFO=`cat /sys/class/power_supply/gpio-charger/online` # A/C online or offline
RAW_VOLTAGE=`cat /sys/bus/iio/devices/iio:device0/in_voltage2_raw` # Raw battery voltage
VOLTAGE_SCALE=`cat /sys/bus/iio/devices/iio:device0/in_voltage_scale` # Voltage scaling
CRITICAL_MV=916 # Your shutdown threshold, default script value is 916
CURRENT_MV=`echo "$RAW_VOLTAGE * $VOLTAGE_SCALE" | bc` # Converts raw voltage into ADS mV
FILE_LOCATION="/root/LOW_BATTERY" # Set another log location here, if you like

#<- Logs to your file when A/C is down.  Comment out if you don't care about this.
if [[ $BATTINFO -lt 1 ]]
then
printf "\nTick . . .          " >> $FILE_LOCATION
echo `date +"%A, %B %d, %Y . . . %r . . .%n"` >> $FILE_LOCATION
printf "Current battery:  "$CURRENT_MV" mV\t\tCritical threshold:  "$CRITICAL_MV" mV\n" >> $FILE_LOCATION
fi
#<- End of A/C down logging.

#<-- Main powerdown checking starts here.
if [[ $BATTINFO -lt 1 && `echo $CURRENT_MV | awk '{print int($1)}'` -lt $CRITICAL_MV ]]
then

#<--- Shutdown logging.  Comment out if you don't care about this.
printf "\n--------------------------------------------------------------------------------\n"
printf "Critical threshold!\n"
echo `date` >> $FILE_LOCATION
printf "KOBOL was forced to shutdown due to low battery status and main power offline!\n" >> $FILE_LOCATION
printf "--------------------------------------------------------------------------------\n" >> $FILE_LOCATION
#<--- End of shutdown logging.

shutdown -h now
fi
#<-- Main powerdown checking ends here.


 

 

Let me know how it works for you, if you use it.  I've been testing it for the past couple of days, and it's worked as intended.  I'm always open to code tips, and I'm still learning, so any advice is appreciated.

Link to post
Share on other sites
Armbian is a community driven open source project. Do you like to contribute your code?

Looks pretty good man!  Thanks for sharing!

 

In fact, I only decide to write the following because you asked.  ;)  So the following are, at best, quite minor (hopefully constructive) criticisms.  What you wrote is perfectly fine, I have certainly seen much worse.  :thumbup:

 

34 minutes ago, Chris Bognar said:

code tips

 

I would probably put the variable comments on a line above each variable, so they are not so long.  Maybe even with a line between each variable.  For readability.

 

For same reasons, I would indent that loop so it's easier to see what's going on.  A proper editor will do this for you.

 

It's also generally considered good form to keep it under 80 chars wide.  You look like you are pretty close.  Some times can't be avoided with things like those long printf statements.  Having said that, if you ever looked at Armbian scripts themselves, you will see they certainly don't follow that.  :D

 

There are some style guides around for shell scripts (and other languages).  Also the Wooledge Bash FAQ is very good (substance more than style), I learned a lot there.

 

Personally, I like to use a lot more white space and (in general) write plenty comments explaining things (although comments are not as much needed in the case of such a simple script as this one).  Example here.  I don't understand why people cram all their scripts together so much, it's not like we have to pay by the line/character or something.  :D  Not saying you are, just in general I mean.

 

Cheers!  :beer:

Link to post
Share on other sites

@Chris Bognar Nice script :thumbup:

 

Actually we already implemented in latest release an auto graceful shutdown when system has been running on battery for more than 10min. https://github.com/armbian/build/pull/2376

It's all done with udev rules and systemd unit file so in a way it's pretty elegant :P but pretty simple.

 

We are still planning to deliver at some point an helios64 service daemon that will manage the UPS feature in more advanced way as you are doing ( and to make it easy to configure / manage in OMV too). Other feature of this dedicated helios64 daemon is to control the fan is a more smart way, taking in consideration HDD temperature.

 

Anyhow cool script and thanks for sharing it here, I'm sure it will interest many.

 

(side note: I agree with @TRS-80 a bit compact  and not easy to read, and would nicer as a script trigger by systemd timer)

Link to post
Share on other sites
  • gprovost changed the title to Script to check the power status, and shutdown if battery is low!

I haven't done much work outside of shell scripting and config files, and I'm not experienced enough to work inside the systemd framework for fear of trashing the system beyond my knowledge.  I've been reading the bash guide TRS-80 offered as a reference, and I've come away with a better understanding of some of the more complex ideas, but I've been browsing it for 3 days and still have quite a bit to read and absorb.  Many thanks for his advice and fast replies.

 

Here is a cleaned up, easier to read version of my original script . . . I haven't modified it operationally because it works like I need it to, but hopefully my style will improve as I get more involved with it.  Also thanks to gprovost for his quick replies and exceptional help to the community as a whole.  This is truly a fantastic machine and labor of love for the KOBOL team.

 

Spoiler

#!/bin/bash

### Basic calls for power stats and variables
	# A/C online or offline
	BATTINFO=`cat /sys/class/power_supply/gpio-charger/online`

	# Raw battery voltage
	RAW_VOLTAGE=`cat /sys/bus/iio/devices/iio:device0/in_voltage2_raw`

	# Voltage scaling
	VOLTAGE_SCALE=`cat /sys/bus/iio/devices/iio:device0/in_voltage_scale`

	# Your shutdown threshold, default script value is 916
	CRITICAL_MV=916

	# Converts raw voltage into ADS mV
	CURRENT_MV=`echo "$RAW_VOLTAGE * $VOLTAGE_SCALE" | bc`

	# Set another log location here, if you like
	FILE_LOCATION="/root/LOW_BATTERY"
### End of variable and call block


### Logs to your file when A/C is down, every minute with battery status.
### If power is restored, logging stops.
### Comment out if you don't care about this.

if [[ $BATTINFO -lt 1 ]]
then
	printf "\nTick . . .          " >> $FILE_LOCATION
	echo `date +"%A, %B %d, %Y . . . %r . . .%n"` >> $FILE_LOCATION
	printf "Battery:  "$CURRENT_MV" mV\t\tCritcal:  "$CRITICAL_MV" mV\n" >> $FILE_LOCATION
fi

### End of A/C down logging.


### Main powerdown checking starts here.

if [[ $BATTINFO -lt 1 && `echo $CURRENT_MV | awk '{print int($1)}'` -lt $CRITICAL_MV ]]
then

	### Shutdown logging.  Logs only when this script calls a shutdown.
	### If power is restored before the battery reaches the threshhold,
	### no shutdown will occur.

	printf "\n-------------------------------------------------\n"
	printf "Critical threshold!\n"
	echo `date` >> $FILE_LOCATION
	printf "Shutdown due to low battery and main power offline!\n" >> $FILE_LOCATION
	printf "---------------------------------------------------\n" >> $FILE_LOCATION

	### End of shutdown logging.


	### And since we have both power down AND critical threshold, shutdown is called.

	shutdown -h now
fi

### Main powerdown checking ends here, along with script.
### The script won't be called again for one minute, so will not run
### again unless your box takes more than one minute to shut down.

 

 

 

Edited by TRS-80
put long output inside spoiler
Link to post
Share on other sites
1 hour ago, Chris Bognar said:

I've been reading the bash guide TRS-80 offered as a reference, and I've come away with a better understanding of some of the more complex ideas, but I've been browsing it for 3 days and still have quite a bit to read and absorb.

 

Dude, I have been visiting there (on and off) for years, and even then, usually only to look up whatever I am interested in at the time!  I therefore applaud your effort...  :D  :beer:

 

Looking better!  Couple more minor feedback, only because of my autism / ADD I cannot help myself:  :D

 

# You can put this all on same line, loks nicer, IMO:

if [[ $BATTINFO -lt 1 ]]; then

    # do stuff

fi

 

Personally I would also not indent the variable declarations, nor put comments at ends of processes unless there was some reason to.  But I gave you enough grief already.  :D

 

You will find your own style in time (for your own stuff; when contributing you always want to just follow the style of the project).  I also learned a lot by studying other people's code.

 

Next thing you know, you will be submitting patches to Armbian build scripts...  :beer:

Link to post
Share on other sites