32

Just yesterday I migrated from Ubuntu 18.04 to Ubuntu 20.04. In 18.04 there was a software called "Battery Monitor" that monitors your battery percentage and notifies you when your battery percentage as reached low level.

I tried to install it in 20.04 but it seems it was not made compatible for it or maybe I am doing something wrong...

Can anyone please help me with this or find me an alternative?

My most important need is to be notified when my battery percentage goes below a certain number.

Thank you

6 Answers6

32

I have Ubuntu Budgie 20.04 and this worked for me:

cd /etc/UPower
sudo nano UPower.conf

If you set UsePercentageForPolicy=true then edit the percentage lines to your liking, such as:

PercentageLow=50
PercentageCritical=35

If you prefer a time based approach then set UsePercentageForPolicy to false and set the time notification options to your liking, such as:

TimeLow=1200
TimeCritical=300

Hit ctrl+X to save the UPower.conf file and close out of nano editor.
Reboot computer or sudo systemctl restart upower for changes to take effect.

By doing this I was able to get the low and critical battery notifications. The pop-up notification only displays for about 2 seconds. Here is what it looks like: enter image description here

Tuna
  • 195
hoatzin
  • 647
6

After a lot of research, here's a script that works perfectly - and gives persistent notifications for both high and low battery ;)

Procedure

  1. Store the script (written below) in some folder (like a folder named scripts in the home directory)
  2. Open terminal and type: crontab -e
  3. Add this line to run the script automatically every 2 minutes: (Note: I've kept the script's name as battery notifications)

*/2 * * * * bash /home/garmadon/scripts/battery-notifications.sh

  1. Press Ctrl + x and then enter to exit and save the crontab.
  2. Log out and log into the system (or restart) to see the effect.

The script

#!/bin/bash

export XDG_RUNTIME_DIR=/run/user/$(id -u)

V1="Charging"

V2=$(grep -w "Charging" /sys/class/power_supply/BAT0/status)

V3=$(grep -Eo '[0-9]{1,}' /sys/class/power_supply/BAT0/capacity)

if [ "$V1" = "$V2" ] && [ "$V3" -ge 85 ]; then notify-send -u critical "Remove Charger!" fi

U1="Discharging"

U2=$(grep -w "Discharging" /sys/class/power_supply/BAT0/status)

if [ "$U1" = "$U2" ] && [ "$V3" -le 45 ]; then notify-send -u critical "Plug in Charger!" fi

Note:

  1. I'm on ubuntu 20.04
  2. I've kept 85% and 45% as the notification level, you can modify them according to your needs.
  3. This script gives persistent notifications that won't go away until you click on them. This comes in handy if you are away from your laptop and hence prevents you from missing the reminder.

Learn more about cron here:

  1. https://www.geeksforgeeks.org/crontab-in-linux-with-examples/
  2. https://crontab.guru
6

A slight variation on Ensei_Tankado's answer that doesn't result in multiple notifications piling-up.

Same Procedure, different Script:

#!/bin/bash

export XDG_RUNTIME_DIR=/run/user/$(id -u)

V1="Charging"

V2=$(grep -w "Charging" /sys/class/power_supply/BAT0/status)

V3=$(grep -Eo '[0-9]{1,}' /sys/class/power_supply/BAT0/capacity)

if [ "$V1" = "$V2" ]; then rm -f "/tmp/battery-notification-low" if [ "$V3" -ge 80 ] && [[ ! -f "/tmp/battery-notification-high" ]]; then touch "/tmp/battery-notification-high" notify-send -u critical "Battery High" "Remove Charger" fi fi

U1="Discharging"

U2=$(grep -w "Discharging" /sys/class/power_supply/BAT0/status)

if [ "$U1" = "$U2" ]; then rm -f "/tmp/battery-notification-high" if [ "$V3" -le 40 ] && [[ ! -f "/tmp/battery-notification-low" ]]; then touch "/tmp/battery-notification-low" notify-send -u critical "Battery Low" "Plug in Charger" fi fi

1

Could be very related as i ended up looking into how to restore battery indicator

$ sudo systemctl restart upower

Job for upower.service failed because a fatal signal was delivered to the control process. See "systemctl status upower.service" and "journalctl -xe" for details.

$ systemctl --failed

UNIT LOAD ACTIVE SUB DESCRIPTION
● upower.service loaded failed failed Daemon for power management

so i had to install

$ sudo apt install systemd:amd64 systemd-timesyncd:amd64

and now service started and battery indicator is back

$ sudo systemctl start upower
Tim
  • 11
0

I came to this workaround:

Works in ubuntu 20

Dependencies

sudo apt install gir1.2-appindicator3-0.1 acpi libappindicator3-1
sudo apt install libnotify4 libgirepository1.0-dev libcairo2

python3 -m pip install pycairo

1. Download source

cd ~/Downloads/
wget https://github.com/maateen/battery-monitor/archive/master.zip
unzip master.zip
cd battery-monitor-master/

2. Modification of Makefile

nano Makefile (3 changes)

1. change sh in first line to bash

2. change from:

PREFIX ?= /usr

to:

PREFIX ?= /home/USERNAME/.local

3 change python version in two! lines

from:

python setup.py clean/install

to:

python3 setup.py clean/install

3. Install as root

sudo su
export PYTHONPATH=/home/USERNAME/.local/lib/python3.8/site-packages/
make install
exit

4. Run as non-root

nohup battery-monitor &

5. A fix in Notification.py for the proper working of upper warning

I know it is odd but, I had to fix this:
#                                     ↓↓↓ your python version of install             ↓↓↓ your python version
sudo nano /home/USERNAME/.local/lib/python3.8/site-packages/battery_monitor-0.0.0-py3.8.egg/battery_monitor/Notification.py
# change the old lines with the new ones
         elif state == 'charging':
NEW            if (percentage >= self.upper_threshold_warning and
OLD            if (percentage != self.last_percentage and
                 remaining != "discharging at zero rate - will never fully discharge" and
                 self.last_notification != "upper_threshold_warning"):
                     self.last_percentage = percentage
NEW                  self.last_notification = "upper_threshold_warning"
OLD                  self.last_notification!="upper_threshold_warning"
                     self.show_notification(type="upper_threshold_warning",
                                            battery_percentage=percentage,
                                            remaining_time=remaining)

Related: https://www.linuxquestions.org/questions/slackware-14/help-to-build-libindicator-libappindicator-for-battery-monitor-4175668385/

Ferroao
  • 959
0

power_status_notification_image


Sometimes while working on my laptop, when not connected to the AC power source, I get notified when power is critically low. I wrote this script which notifies me for every steps of 10% change in power level (for more details, please refer to the script code). For notification I preferred using zenity to notify-send as I frequently miss out to check such toast notifications while busy.

UPDATE: Now, also shows charging/discharging rates.

Script name: /home/username/bin/notification_battery_discharge.sh ;

Contents:

#!/bin/bash

notification_battery_discharge.sh (v1.0)

declare __SCRIPT_NAME="${0##*/}"

Configuration options:

declare -i __DISPLAY_CHARGING_NOTIFICATIONS=1 ## where, 1=true, 0=false declare __FILENAME="/sys/class/power_supply/BAT1/uevent" declare __FILE_LOG="/tmp/${__SCRIPT_NAME}.log"

declare -i __FLAG__BATTERY_CHARGING_STATE=0 ## 0=Discharging, 1=Charging declare -i __FLAG__BATTERY_CHARGING_STATE_TOGGLED=0 ## 0=notToggled, 1=toggled during current iteration declare -i __FLAG__STARTING_BATTERY_PERCENTAGE_SET=0

declare -ri __TIME_SLEEP_SECONDS=60 declare __CURR_POWER_SUPPLY_STATUS="" declare -i __CURR_BATTERY_PERCENTAGE_LEVEL=0 declare -i __STARTING_BATTERY_PERCENTAGE_LEVEL=0 declare -i __DIFF_BATTERY_PERCENTAGE_LEVEL=0 declare -i __LOWER_LEVEL=0 declare -i __UPPER_LEVEL=0

declare -i __SECONDS_STARTING=${SECONDS} declare -i __SECONDS_NOW=0 declare -i __SECONDS_DIFF=0

declare __RATE_OF_DISCHARGE_PER_MIN=0 declare __RATE_OF_DISCHARGE_PER_HOUR=0

declare -A __LEVEL __LEVEL["90-100"]=0 ## where, 1=true; 0=false __LEVEL["80-90"]=0 __LEVEL["70-80"]=0 __LEVEL["60-70"]=0 __LEVEL["50-60"]=0 __LEVEL["40-50"]=0 __LEVEL["30-40"]=0 __LEVEL["20-30"]=0 __LEVEL["10-20"]=0 __LEVEL["0-10"]=0 declare -A __LEVEL_MSG_DISPLAYED __LEVEL_MSG_DISPLAYED["90-100"]=0 ## where, 1=true; 0=false __LEVEL_MSG_DISPLAYED["80-90"]=0 __LEVEL_MSG_DISPLAYED["70-80"]=0 __LEVEL_MSG_DISPLAYED["60-70"]=0 __LEVEL_MSG_DISPLAYED["50-60"]=0 __LEVEL_MSG_DISPLAYED["40-50"]=0 __LEVEL_MSG_DISPLAYED["30-40"]=0 __LEVEL_MSG_DISPLAYED["20-30"]=0 __LEVEL_MSG_DISPLAYED["10-20"]=0 __LEVEL_MSG_DISPLAYED["0-10"]=0

function setBatteryChargingStatusFlag() { declare -i power_supply_status_initial=${__FLAG__BATTERY_CHARGING_STATE} if [[ "${__CURR_POWER_SUPPLY_STATUS}" == "Discharging" ]] ; then __FLAG__BATTERY_CHARGING_STATE=0 fi if [[ "${__CURR_POWER_SUPPLY_STATUS}" == "Charging" || "${__CURR_POWER_SUPPLY_STATUS}" == "Full" ]] ; then __FLAG__BATTERY_CHARGING_STATE=1 fi declare -i power_supply_status_latter=${__FLAG__BATTERY_CHARGING_STATE} if [[ ${power_supply_status_initial} -ne ${power_supply_status_latter} ]] ; then __FLAG__BATTERY_CHARGING_STATE_TOGGLED=1 else __FLAG__BATTERY_CHARGING_STATE_TOGGLED=0 fi }

function checkLevel() { declare myLevel="${1}" ## $1 is required to be level string e.g. "80-90"

if [[ ${__LEVEL[${myLevel}]} -eq 1 && ${__LEVEL_MSG_DISPLAYED[${myLevel}]} -eq 0 ]] ; then
    if [[ "${__CURR_POWER_SUPPLY_STATUS}" != "Discharging" ]] ; then
        if [[ ${__DISPLAY_CHARGING_NOTIFICATIONS} -eq 1 ]] ; then
            ## Charging notification:
            zenity --info --title="Battery Status: ${__CURR_POWER_SUPPLY_STATUS} ($(date +%Y-%m-%d' '%H:%M))" --text="The power supply is currently ${__CURR_POWER_SUPPLY_STATUS} at level ${__CURR_BATTERY_PERCENTAGE_LEVEL}%. Charging rate is ${__RATE_OF_DISCHARGE_PER_HOUR}%/hour (${__RATE_OF_DISCHARGE_PER_MIN}%/minute)." &
        fi
    else
        ## Discharging notification:
        zenity --error --title="Battery Status: ${__CURR_POWER_SUPPLY_STATUS} ($(date +%Y-%m-%d' '%H:%M))" --text="The power supply is currently ${__CURR_POWER_SUPPLY_STATUS} at level ${__CURR_BATTERY_PERCENTAGE_LEVEL}%. Discharging rate is ${__RATE_OF_DISCHARGE_PER_HOUR}%/hour (${__RATE_OF_DISCHARGE_PER_MIN}%/minute)." &
    fi
    __LEVEL_MSG_DISPLAYED[${myLevel}]=1
fi
if [[ ${__LEVEL[${myLevel}]} -eq 0 && ${__LEVEL_MSG_DISPLAYED[${myLevel}]} -eq 1 ]] ; then
    __LEVEL_MSG_DISPLAYED[${myLevel}]=0
fi

}

Execution start:

while : ; do while read ; do if [[ "${REPLY}" =~ ^POWER_SUPPLY_STATUS=(.*)$ ]] ; then __CURR_POWER_SUPPLY_STATUS=${BASH_REMATCH[1]} fi ## Set __CURR_BATTERY_PERCENTAGE_LEVEL : if [[ "${REPLY}" =~ ^POWER_SUPPLY_CAPACITY=(.*)$ ]] ; then __CURR_BATTERY_PERCENTAGE_LEVEL=${BASH_REMATCH[1]} fi done < "${__FILENAME}"

if [[ ${__FLAG__STARTING_BATTERY_PERCENTAGE_SET} -eq 0 ]] ; then
    __FLAG__STARTING_BATTERY_PERCENTAGE_SET=1
    __STARTING_BATTERY_PERCENTAGE_LEVEL=${__CURR_BATTERY_PERCENTAGE_LEVEL}
fi

## Now, since we have __CURR_POWER_SUPPLY_STATUS variable set, we call function:
setBatteryChargingStatusFlag

if [[ ${__FLAG__BATTERY_CHARGING_STATE_TOGGLED} -eq 1 ]] ; then
    __SECONDS_STARTING=${SECONDS}
    __STARTING_BATTERY_PERCENTAGE_LEVEL=${__CURR_BATTERY_PERCENTAGE_LEVEL}
fi

if [[ &quot;${__CURR_POWER_SUPPLY_STATUS}&quot; == &quot;Discharging&quot; ]] ; then
    __SECONDS_NOW=${SECONDS}
    let &quot;__SECONDS_DIFF = __SECONDS_NOW - __SECONDS_STARTING&quot;
    if [[ ${__SECONDS_DIFF} -eq 0 ]] ; then
        __SECONDS_DIFF=1 ## Assign minimum value of __SECONDS_DIFF as 1 instead of zero.
    fi
    ## For Discharging, starting percentage is higher than later percentage, so:
    let &quot;__DIFF_BATTERY_PERCENTAGE_LEVEL = __STARTING_BATTERY_PERCENTAGE_LEVEL - __CURR_BATTERY_PERCENTAGE_LEVEL&quot;
    __RATE_OF_DISCHARGE_PER_MIN=&quot;$( echo &quot;scale=3; ( ${__DIFF_BATTERY_PERCENTAGE_LEVEL} * 60 ) / ${__SECONDS_DIFF}&quot; | bc )&quot;
    __RATE_OF_DISCHARGE_PER_HOUR=&quot;$( echo &quot;scale=3; ( ${__DIFF_BATTERY_PERCENTAGE_LEVEL} * 60 * 60 ) / ${__SECONDS_DIFF}&quot; | bc )&quot;
    # echo &quot;$(date +%H:%M:%S) :: Discharging :: __RATE_OF_DISCHARGE_PER_MIN=$__RATE_OF_DISCHARGE_PER_MIN , __RATE_OF_DISCHARGE_PER_HOUR=$__RATE_OF_DISCHARGE_PER_HOUR&quot; &gt;&gt; &quot;$__FILE_LOG&quot;
fi

if [[ &quot;${__CURR_POWER_SUPPLY_STATUS}&quot; == &quot;Charging&quot; ]] ; then
    __SECONDS_NOW=${SECONDS}
    let &quot;__SECONDS_DIFF = __SECONDS_NOW - __SECONDS_STARTING&quot;
    if [[ ${__SECONDS_DIFF} -eq 0 ]] ; then
        __SECONDS_DIFF=1 ## Assign minimum value of __SECONDS_DIFF as 1 instead of zero.
    fi
    ## For Charging, starting percentage is lower than later percentage. Also,
    ## for charging, the __RATE_OF_DISCHARGE_PER_MIN and __RATE_OF_DISCHARGE_PER_HOUR
    ## actually reflect rate of charging instead.
    let &quot;__DIFF_BATTERY_PERCENTAGE_LEVEL = __CURR_BATTERY_PERCENTAGE_LEVEL - __STARTING_BATTERY_PERCENTAGE_LEVEL&quot;
    __RATE_OF_DISCHARGE_PER_MIN=&quot;$( echo &quot;scale=3; ( ${__DIFF_BATTERY_PERCENTAGE_LEVEL} * 60 ) / ${__SECONDS_DIFF}&quot; | bc )&quot;
    __RATE_OF_DISCHARGE_PER_HOUR=&quot;$( echo &quot;scale=3; ( ${__DIFF_BATTERY_PERCENTAGE_LEVEL} * 60 * 60 ) / ${__SECONDS_DIFF}&quot; | bc )&quot;
    # echo &quot;$(date +%H:%M:%S) :: Charging    :: __RATE_OF_CHARGING_PER_MIN=$__RATE_OF_DISCHARGE_PER_MIN , __RATE_OF_CHARGING_PER_HOUR=$__RATE_OF_DISCHARGE_PER_HOUR&quot; &gt;&gt; &quot;$__FILE_LOG&quot;
fi


__LOWER_LEVEL=90
__UPPER_LEVEL=100
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=80
__UPPER_LEVEL=90
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=70
__UPPER_LEVEL=80
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=60
__UPPER_LEVEL=70
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=50
__UPPER_LEVEL=60
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=40
__UPPER_LEVEL=50
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=30
__UPPER_LEVEL=40
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=20
__UPPER_LEVEL=30
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=10
__UPPER_LEVEL=20
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

__LOWER_LEVEL=0
__UPPER_LEVEL=10
if [[ ${__CURR_BATTERY_PERCENTAGE_LEVEL} -ge ${__LOWER_LEVEL} &amp;&amp; ${__CURR_BATTERY_PERCENTAGE_LEVEL} -lt ${__UPPER_LEVEL} ]] ; then
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=1
else
    __LEVEL[&quot;${__LOWER_LEVEL}-${__UPPER_LEVEL}&quot;]=0
fi

checkLevel &quot;90-100&quot;
checkLevel &quot;80-90&quot;
checkLevel &quot;70-80&quot;
checkLevel &quot;60-70&quot;
checkLevel &quot;50-60&quot;
checkLevel &quot;40-50&quot;
checkLevel &quot;30-40&quot;
checkLevel &quot;20-30&quot;
checkLevel &quot;10-20&quot;
checkLevel &quot;0-10&quot;

sleep ${__TIME_SLEEP_SECONDS}s

done

End of script.

Configuration: Appropriately fix the __FILENAME variable to point to /sys/class/power_supply/BAT0/uevent or /sys/class/power_supply/BAT1/uevent or something else as needed. If you don't want the notification during charging use __DISPLAY_CHARGING_NOTIFICATIONS=0 .

The script can be started manually by running bash /home/username/bin/notification_battery_discharge.sh .

Setup:

For automatic startup, create a .desktop file in $HOME/.config/autostart e.g. /home/username/.config/autostart/notification_battery_discharge.desktop with the following content:

[Desktop Entry]
Name=Notification of Battery Discharge
Exec="/home/username/bin/notification_battery_discharge.sh"
Type=Application

If required run chmod +x /home/username/.config/autostart/notification_battery_discharge.desktop . Then log out, and log back in, the script should start its notification process.

Alternatively, for automatic start up using systemd, create a .service file in $HOME/.config/systemd/user/ directory e.g. $HOME/.config/systemd/user/notification_battery_discharge.service with the following content:

[Unit]
Description=Display notification at different levels of battery discharging/charging.
After=graphical-session.target

[Service] Type=oneshot ExecStart=-/bin/bash -c '/home/username/bin/notification_battery_discharge.sh'

[Install] WantedBy=graphical-session.target

Then use the command systemctl --user enable notification_battery_discharge.service then log out, and log back in. The notification process should start.

rusty
  • 16,917