ThinkPad T440s Battery Warning Script for Ubuntu 16.04

Since I started with a stripped-down Ubuntu install that doesn’t include much in the way of power management I made a tool to warn me when my battery is low and to suspend the system when it is low enough. I borrowed some content and structure from this script, adding features to meet my own needs, in particular support for a second battery, notifications, and auto-suspend.

This script assumes you’ve got two batteries and will warn when both batteries are discharging or discharged (status = “unknown”) and both have remaining power below a certain threshold.

It saves status files in ~/tmp as per the TMPDIR variable at the top to keep from notifying you every minute or however often you choose to have this run. Those files are cleared when either of the batteries begins charging.

At 15% remaining a notification is given through the dbus desktop notification system. At 10% another notification is issued and a sound played. At 8% another notification is given, and a 15 second timer started, after which the system is suspended.

#!/bin/bash

#get access to the dbus session for desktop notifications - must be used inconjunction with the other script run at startup to populate this file with that session information
if [ -r "$HOME/.dbus/Xdbus" ]; then
    . "$HOME/.dbus/Xdbus"
fi

TMPDIR="$HOME/tmp/"
BASEDIR="/sys/class/power_supply/"
DIR1="$BASEDIR/BAT0"
DIR2="$BASEDIR/BAT1"

STAT1=$(cat "$DIR1/status")
STAT2=$(cat "$DIR2/status")

echo "Battery1: $STAT1"
echo "Battery2: $STAT2"

#if both batteries are either discharging or discharged (status unknown)
if [ \( "$STAT1" = "Discharging" -o "$STAT1" = "Unknown" \) -a \( "$STAT2" = "Discharging" -o "$STAT2" = "Unknown" \) ];
then
        REM1=$(cat "$DIR1/energy_now")
        REM2=$(cat "$DIR2/energy_now")
        FULL1=$(cat "$DIR1/energy_full")
        FULL2=$(cat "$DIR2/energy_full")
        PRCT1=$((100 * $REM1 / $FULL1))
        PRCT2=$((100 * $REM2 / $FULL2))

        echo "Power - Battery1: $PRCT1%, Battery2: $PRCT2%"

        if [ $PRCT1 -le 8 ] && [ $PRCT2 -le 8 ];
        then
                notify-send "Battery Critical" "Suspending while there's a little juice left. You have 15 seconds."
                #you will not hear this if the sound is muted - assuming if the sound is muted it should stay that way.
                paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
                sleep 15
                sudo systemctl suspend
        elif [ $PRCT1 -le 10 ] && [ $PRCT2 -le 10 ];
        then
                if [ ! -f $TMPDIR/battwarn10 ];
                then
                        notify-send "Battery Low" "Remaining battery is at 10% or lower"
                        #you will not hear this if the sound is muted - assuming if the sound is muted it should stay that way.
                        paplay /usr/share/sounds/freedesktop/stereo/suspend-error.oga
                        touch $TMPDIR/battwarn10
                fi
        elif [ $PRCT1 -le 15 ] && [ $PRCT2 -le 15 ];
        then
                if [ ! -f $TMPDIR/battwarn15 ];
                then
                        notify-send "Battery Low" "Remaining battery is at 15% or lower"
                        touch $TMPDIR/battwarn15
                fi
        fi
elif [ "$STAT1" = "Charging" ] || [ "$STAT2" = "Charging" ];
then
        #if the status is charging, clear the temp files
        if [ -f $TMPDIR/battwarn15 ];
        then
                rm $TMPDIR/battwarn15
        fi
        if [ -f $TMPDIR/battwarn10 ];
        then
                rm $TMPDIR/battwarn10
        fi
fi
exit 0

To get this working you’ll need to do a few things. First up, make sure ~/tmp exists, or change the TMPDIR variable to a suitable location with write permissions for your user.

You’ll also need to install this script in ~/bin or another suitable location, then configure it to launch on startup (such as in an i3 config). This script creates a means for the power script to access the dbus session for desktop notifications. The script came from this answer on stack exchange.

#!/bin/sh

#include the following in a script that needs access to the dbus session
#if [ -r "$HOME/.dbus/Xdbus" ]; then
#    . "$HOME/.dbus/Xdbus"
#fi

FILE=$HOME/.dbus/Xdbus

touch $FILE
chmod 600 $FILE
env | grep DBUS_SESSION_BUS_ADDRESS > $FILE
echo 'export DBUS_SESSION_BUS_ADDRESS' >> $FILE

exit 0

To make suspend work you’ll need to run

sudo visudo

and add a line like the following

%sudo ALL = NOPASSWD: /bin/systemctl suspend

This allows all users with sudo access to run the command to suspend using sudo without a password, which means we can run it from the script without asking for a password. If you’d prefer to allow this for just your user, replace %sudo with your user name.

Lastly, you’ll need to configure your crontab to execute this script at routine intervals. I chose every two minutes.

Run the following to edit your crontab:

crontab -e

And add this line:

*/2 * * * * /home/user/bin/power_status

Of course, make sure to replace with the path to your script. If you haven’t already, make sure the script is executable by running the following on it.

chmod +x power_status

Cheers!