There are two files to the solution, and their source is posted in order.
- com.local.battery_percent.plist
- battery_percent.sh
Ultimately, they will be copied into your local Library LaunchAgents (~/Library/LaunchAgents) folder. You must logout/log in to activate the LaunchAgent.
You copy/paste each one into a separate editor session, and save with the above names. Before you save the .plist, replace my username with your own, and full paths are required. Edit the integer that is the lowest battery percentage that you will allow before receiving low battery prompts. If you don't want it running every 15 minutes, change the StartInverval integer value per the comment.
The only change that is necessary to the Bash script is possibly that you do not want a dull grey background, and I have provided other customBg color values if needed.
The following are scrollable panels, so click at the top, and then drag downward to allow selection of the entire code. The code will not display correctly while signed out of the community.
Source for com.local.battery_percent.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Disabled</key> <false/> <key>RunAtLoad</key> <true/> <key>KeepAlive</key> <false/> <key>Label</key> <string>com.local.battery_percent.plist</string> <!-- 3600 hourly, 1800 every 30 min, 900 every 15 min --> <key>StartInterval</key> <integer>900</integer> <key>Program</key> <string>/Users/viking/Library/LaunchAgents/battery_percent.sh</string> <key>ProgramArguments</key> <array> <string>/Users/viking/Library/LaunchAgents/battery_percent.sh</string> <!-- minimum battery percentage to start warnings this value will be passed as argument to program --> <string>90</string> </array> </dict> </plist>
Source for battery_percent.sh
#!/bin/bash
# calculate the percentage of remaining battery.
# tested with High Sierra 10.13.4 on a 2014 MacBook Air
BATTERY_INSTALLED=
# returns "Battery Power" or "AC Power"
CHARGING_STATUS="$(pmset -g ps | egrep -iow '(Battery Power|AC Power)')"
# the LaunchAgent will pass this value into the script when it runs
BATTERY_MIN=$1
battery_warn () {
/usr/bin/python <<'EOF' - "$1"
from Foundation import NSString, NSArray, NSMakeRect
from AppKit import NSColor, NSAlert, NSStatusWindowLevel, NSFont, NSView
import ast
import sys
# because it is an enumerator in Objective-C
NSAlertStyleCritical = 2
if not len(sys.argv) == 2:
sys.exit('Wrong number of arguments')
# pass the numeric string in as an unmolested integer
bat_remain = ast.literal_eval(sys.argv[1])
# make a custom blue background color
# customBg = NSColor.colorWithDeviceRed_green_blue_alpha_(0.152, 0.671, 0.966, 1.0)
# customBg = NSColor.yellowColor()
# customBg = NSColor.redColor()
customBg = NSColor.systemGrayColor() # start with conservative dialog
alert = NSAlert.alloc().init()
alert.window().setTitle_("Battery Charge Monitor")
alert.window().setLevel_(NSStatusWindowLevel)
alert.window().setBackgroundColor_(customBg)
alert.setAlertStyle_(NSAlertStyleCritical)
msg_font = NSFont.boldSystemFontOfSize_(18.0)
inform_font = NSFont.boldSystemFontOfSize_(18.0)
bat_text = NSString.alloc().init()
bat_text = "Battery Remaining: {} Percent".format(bat_remain)
inform_text = NSString.alloc().initWithString_("Time to Recharge")
# now override the message and informative text fields of the alert panel
view = NSArray.array()
view = alert.window().contentView().subviews()
view[4].setFont_(msg_font)
view[4].setStringValue_(bat_text)
view[5].setFont_(inform_font)
view[5].setStringValue_(inform_text)
# make the alert window slightly wider than default
accview = NSView.alloc().initWithFrame_(NSMakeRect(0, 0, 350, 0))
alert.setAccessoryView_(accview)
alert.runModal()
EOF
}
# returns Yes or No
BATTERY_INSTALLED="$(ioreg -l -k "AppleSmartBattery" | \
egrep -io '("BatteryInstalled") = \w+' | awk '{print $3}')"
[[ $BATTERY_INSTALLED = "" ]] || [[ $BATTERY_INSTALLED = "No" ]] && \
echo "No battery Installed." && exit 1
# only produce warning dialogs when on battery power
[[ $CHARGING_STATUS = "AC Power" ]] && exit 1
# remaining battery percentage using Apple's calculations
BATTERY_PERCENT=$(pmset -g ps | perl -lne '$_ =~ /(\d+)(?=%;)/s && print $1;')
[[ $BATTERY_PERCENT > $BATTERY_MIN ]] && exit 0
battery_warn "${BATTERY_PERCENT}"
exit 0