Skip to content

Instantly share code, notes, and snippets.

@akomakom
Last active March 25, 2023 06:49
Show Gist options
  • Save akomakom/f9cf1f716fdadce2a7a7bc2cd6d3edde to your computer and use it in GitHub Desktop.
Save akomakom/f9cf1f716fdadce2a7a7bc2cd6d3edde to your computer and use it in GitHub Desktop.
Play periodic sound when laptop battery is low, also when charger is plugged in/unplugged

Suitable for laptops that don't generate udev events when battery charge level changes (but do generate events when unplugged).

Uses MP3 files (use mine or make your own).
You can also change sound() to use a tone as in this example

Installation

  • Copy MP3 files to /usr/local/bin (or change the shell script)
  • Copy other files to the location specified at the top (change "CHANGE_TO_MY_USER" to the username you primarily use)
  • Run the following (to make udev and systemd aware of new config):
chmod a+x /usr/local/bin/battery-warning.sh
systemctl daemon reload 
systemctl enable battery-warning
systemctl start battery-warning

systemctl reload udev
  • Now:
    • Pull the plug and you should hear a sound
    • Plug it back in and you should hear a sound
    • Let the battery discharge below THRESHOLD and you should hear a sound every SLEEP interval
# /etc/udev/rules.d/acplug.rules
# Trigger a script to play a sound when the charger is plugged in or unplugged
ACTION=="change", SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="0", RUN+="/usr/local/bin/battery-warning.sh force"
ACTION=="change", SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="1", RUN+="/usr/local/bin/battery-warning.sh forcehigh"
# In Ubuntu 21.10 I had to change to running the script as my user, or sox couldn't find the audio device
#ACTION=="change", SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="0", RUN+="/usr/bin/su CHANGE_TO_MY_USERNAME -c '/usr/local/bin/battery-warning.sh force'"
#ACTION=="change", SUBSYSTEM=="power_supply", ENV{POWER_SUPPLY_ONLINE}=="1", RUN+="/usr/bin/su CHANGE_TO_MY_USERNAME -c '/usr/local/bin/battery-warning.sh forcehigh'"
# /etc/systemd/system/battery-warning.service
[Unit]
Description=Battery Warning loop that beeps
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User=CHANGE_TO_MY_USER # best not to run as root, and there may be audio device issues too
ExecStart=/usr/local/bin/battery-warning.sh
[Install]
WantedBy=multi-user.target
#!/bin/bash
# /usr/local/bin/battery-warning.sh
#
# Battery warning sound when battery is below THRESHOLD %
# Intended to be started as a systemd service, and also used from udev
#
# Also, $1=force will force it to play the low sound and exit (for udev)
# Also, $1=forcehigh will force it to play the high sound and exit (for udev)
THRESHOLD=20 # percentage
# This file is played every $SLEEP seconds once battery level is below $THRESHOLD
# It is also played when charger is unplugged (if udev rule is configured)
FILE_LOW=/usr/local/bin/low-battery-sound.mp3
# This file is played when the charger is plugged in (if udev rule is configured)
FILE_HIGH=/usr/local/bin/high-battery-sound.mp3
SLEEP=60 # how often to check and alert if below THRESHOLD
sound() {
SOUND=${1:-$FILE_LOW}
XDG_RUNTIME_DIR=/run/user/$UID DISPLAY=:0 /usr/bin/play $SOUND > /dev/null 2>&1
}
if [ "$1" == "force" ] ; then
sound
exit
fi
if [ "$1" == "forcehigh" ] ; then
sound $FILE_HIGH
exit
fi
while true ; do
#PCT=$(acpi -b | grep -oP '\d+(?=%)') # https://unix.stackexchange.com/a/572032/199293
#DISCHARGING=$(acpi -b | grep -i discharging)
# Alternate method:
PCT=$(upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep percentage: | sed 's|[^0-9]*\([0-9]*\)%|\1|')
DISCHARGING=$(upower -i /org/freedesktop/UPower/devices/battery_BAT0 | grep state: | grep discharging)
if [ -n "$DISCHARGING" ] ; then
if [ "$PCT" != "" ] && [ $PCT -lt $THRESHOLD ] ; then
logger -t "akom" "Battery discharging warning: ${PCT}"
sound
fi
fi
sleep $SLEEP
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment