7

Essentially, I would like this comment into a working answer.

I know how to extract the battery percentage from How to check battery status using terminal?:

upower -i $(upower -e | grep BAT) | grep --color=never -E percentage|xargs|cut -d' ' -f2|sed s/%//

And how to pop-up a basic notification:

notify-send "battery low"

But how can I set up a (bash?) script to permanently monitor the output and send notification as per this pseudo-code:

if battery_status < 10% then notify-send "battery low" and put my system to suspended state sudo pm-suspend

landroni
  • 5,941
  • 7
  • 36
  • 58

2 Answers2

7

Step one: make pm-suspend accessible to all users, no password asked

Do sudo visudo and add this line at the end of the file: yourusername ALL=NOPASSWD: /usr/sbin/pm-suspend

Source: How do I run specific sudo commands without a password?

Step two: create batwatch.desktop file:

This is the file that will launch automatically the monitoring script. The file must be stored in $HOME/.config/autostart/ folder.

[Desktop Entry]
Type=Application
Exec=/home/serg/bin/batwatch.sh
Hidden=false
NoDisplay=false
Name=Battery Monitor Script

Notice that the script is in my /home/serg/bin folder. You can use whatever folder you like, but for the sake of standards /usr/bin or /home/username/bin would be more prefered.

Source: How to run a script on startup

Step three:create the actual script, save in the same location as Exec= line

Here's the actual script. Notice, I'm using bash there, but it also should work with korn shell. I added some comments, so read those to understand what the script does exactly

#!/bin/bash

# Check if the battery is connected
if [ -e /sys/class/power_supply/BAT1 ]; then

    # this line is for debugging mostly. Could be removed
    #notify-send --icon=info "STARTED MONITORING BATERY"
    zenity --warning --text "STARTED MONITORING BATERY"

    while true;do   
            # Get the capacity
            CAPACITY=$( cat /sys/class/power_supply/BAT1/uevent | grep -i capacity | cut -d'=' -f2 )

            case $CAPACITY in
            # do stuff when we hit 11 % mark
            [0-9]|11)
                # send warning and suspend only if battery is discharging
                # i.e., no charger connected
                STATUS=$(  cat /sys/class/power_supply/BAT1/uevent | grep -i status | cut -d'=' -f2 )
                 if [ $(echo $STATUS) == "Discharging" ]; then

                    #notify-send --urgency=critical --icon=dialog-warning "LOW BATTERY! SUSPENDING IN 30 sec"
                    zenity --warning --text "LOW BATTERY! SUSPENDING IN 30 sec"
                    sleep 30
                    gnome-screensaver-command -l && sudo pm-suspend
                    break
                 fi
                ;;
            *)
            sleep 1
                continue
                ;;
            esac
    done
fi

Step four: reboot and test if the script works

For this purpose you can adjust the number [0-9]|11) to whatever value you like, for example 65) to suspend at 65%. The you will suspend only if you're not connected to power supply (i.e, not charging).

Let me know if you like this, and if it works, make sure to upvote and click the grey checkmark to the left side of my answer !

Cheers !

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
  • 1
    Note: since we're relying on zenity for notifications ( my notify-send for some reason doesn't work), it will be mostly appropriate for GUI. If you're working exclusively in tty, this won't work. I suggest you use byobu in tty for monitoring battery, or adding this same script to .bashrc file, with zenity lines replaced with echo BATTERY LOW, SUSPENDING IN 30 SEC | wall line – Sergiy Kolodyazhnyy Mar 30 '15 at 23:22
  • Thanks for this. It seems to be working, but one of the issues that I notice is that it takes a lot of processing power. I suspect this comes from the continuous case $CAPACITY in. Is there a way to do the check every 1sec or so? – landroni Mar 31 '15 at 08:18
  • Found how to do this. I edited the script to add notify-send equivalents for those who prefer that, and to make the "loop" happen at 1sec intervals. Works nicely! – landroni Mar 31 '15 at 15:05
  • 1
    Hehe, alright. I was about to edit it to add sleep 30 after the while statement begins to create 30 second delay. Glad you like this script! – Sergiy Kolodyazhnyy Mar 31 '15 at 15:45
  • Ah, I see, you added sleep 1 before continue statement. Yeah, that'll do,too – Sergiy Kolodyazhnyy Mar 31 '15 at 15:52
2

I had made a similar script for my Vaio to notify me when the battery gets fully charged. I had utilised UPOWER to provide me the updates on the battery state and extracted the related section out of these. Here is the code:

#!/bin/bash

while true;do 

STATE=$( upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep "state:" | cut -b 26- )

if [ $STATE = "fully-charged" ]
then 

zenity --info --text "Battery Full!"
break

fi

done
Rubal
  • 121
  • 5
  • 1
    Since your script is pretty short, it would be nice if you copy and paste its contents here too so that readers don't have to click yet another link to get your script. – edwinksl Jul 10 '16 at 18:24
  • If I may suggest, there's couple of improvements you can do to your script. One, get rid of grep "state:" | cut -b 26- and use awk '/state:/{print $2}' . Does the same thing, and instead of two commands , uses one. Less system calls, better performance. Second thing, add sleep 0.25 at the end of your while loop. While loops that continuously run will produce high CPU usage. Otherwise, nice script , good job ! – Sergiy Kolodyazhnyy Jul 11 '16 at 05:19
  • Thanks for the suggestions. Will get them into work and make changes here! – Rubal Jul 11 '16 at 05:36
  • @Rubal also , please get into habit of quoting variables . In this case it is OK , but when a variable has multiple words, the test might fail, better use "$STATE" – Sergiy Kolodyazhnyy Jul 11 '16 at 05:47