2023-12-28 01:53:43 +00:00
#!/bin/sh
2023-07-13 00:40:52 +00:00
#!/usr/bin/env nix-shell
#!nix-shell -i bash
2023-12-28 00:35:48 +00:00
usage() {
echo "usage: battery_estimate [options...]"
echo
echo "pretty-prints a battery estimate (icon to indicate state, and a duration estimate)"
echo
echo "options:"
echo " --debug: output additional information, to stderr"
2023-12-28 03:05:27 +00:00
echo " --minute-suffix <string>: use the provided string as a minutes suffix"
echo " --hour-suffix <string>: use the provided string as an hours suffix"
echo " --icon-suffix <string>: use the provided string as an icon suffix"
2023-12-28 17:43:34 +00:00
echo " --percent-suffix <string>: use the provided string when displaying percents"
2023-12-28 00:35:48 +00:00
}
2023-07-13 00:40:52 +00:00
# these icons come from sxmo; they only render in nerdfonts
2023-12-28 01:11:51 +00:00
icon_bat_chg=("" "" "" "")
icon_bat_dis=("" "" "" "")
2023-12-28 03:05:27 +00:00
suffix_icon=" " # thin space
2023-12-28 17:43:34 +00:00
suffix_percent="%"
2023-12-28 03:05:27 +00:00
# suffix_icon=" "
2023-07-13 00:40:52 +00:00
2023-12-28 01:53:43 +00:00
# render time like: 2ʰ08ᵐ
# unicode sub/super-scripts: <https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts>
2023-12-28 03:05:27 +00:00
# symbol_hr="ʰ"
# symbol_min="ᵐ"
2023-12-28 01:53:43 +00:00
# render time like: 2ₕ08ₘ
# symbol_hr="ₕ"
# symbol_min="ₘ"
# render time like: 2h08m
# symbol_hr="h"
# symbol_min="m"
# render time like: 2:08
# symbol_hr=":"
# symbol_min=
2023-12-28 03:05:27 +00:00
# render time like: 2꞉ 08⧗
symbol_hr="꞉ "
symbol_min="⧗"
# variants:
# symbol_hr=":"
# symbol_min="⧖"
# symbol_min="⌛"
2023-12-28 01:53:43 +00:00
# render time like: 2'08"
# symbol_hr="'"
# symbol_min='"'
2023-12-28 00:35:48 +00:00
log() {
if [ "$BATTERY_ESTIMATE_DEBUG" = "1" ]; then
printf "$@" >&2
echo >&2
fi
}
2023-12-28 01:11:51 +00:00
render_icon() {
# args:
# 1: "chg" or "dis"
# 2: current battery percentage
level=$(($2 / 25))
level=$(($level > 3 ? 3 : $level))
level=$(($level < 0 ? 0 : $level))
log "icon: %s %d" "$1" "$level"
if [ "$1" = "dis" ]; then
printf "%s" "${icon_bat_dis[$level]}"
elif [ "$1" = "chg" ]; then
printf "%s" "${icon_bat_chg[$level]}"
fi
}
2023-11-19 01:49:58 +00:00
try_path() {
2023-12-28 00:41:23 +00:00
# assigns output variables:
2023-12-28 01:11:51 +00:00
# - perc, perc_from_full (0-100)
2023-11-19 01:49:58 +00:00
# - full, rate (pos means charging)
if [ -f "$1/capacity" ]; then
2023-12-28 01:11:51 +00:00
log "perc, perc_from_full from %s" "$1/capacity"
2023-11-19 01:49:58 +00:00
perc=$(cat "$1/capacity")
2023-12-28 01:11:51 +00:00
perc_from_full=$((100 - $perc))
2023-11-19 01:49:58 +00:00
fi
if [ -f "$1/charge_full_design" ] && [ -f "$1/current_now" ]; then
2023-12-28 00:35:48 +00:00
log "full, rate from %s and %s" "$1/charge_full_design" "$1/current_now"
2023-11-19 01:49:58 +00:00
# current is positive when charging
full=$(cat "$1/charge_full_design")
rate=$(cat "$1/current_now")
2023-12-28 00:41:23 +00:00
elif [ -f "$1/energy_full" ] && [ -f "$1/power_now" ]; then
log "full, rate from %s and %s" "$1/energy_full" "$1/power_now"
# power_now is positive when discharging
full=$(cat "$1/energy_full")
rate=-$(cat "$1/power_now")
elif [ -f "$1/energy_full" ] && [ -f "$1/energy_now" ]; then
2023-12-28 00:35:48 +00:00
log "full, rate from %s and %s" "$1/energy_full" "$1/energy_now"
2023-12-28 00:41:23 +00:00
log " this is a compatibility path for legacy Thinkpad batteries which do not populate the 'power_now' field, and incorrectly populate 'energy_now' with power info"
# energy_now is positive when discharging
2023-11-19 01:49:58 +00:00
full=$(cat "$1/energy_full")
rate=-$(cat "$1/energy_now")
fi
}
2023-11-19 01:51:15 +00:00
2023-12-28 00:35:48 +00:00
try_all_paths() {
try_path "/sys/class/power_supply/axp20x-battery" # Pinephone
try_path "/sys/class/power_supply/BAT0" # Thinkpad
2023-12-28 01:11:51 +00:00
log "perc: %d, perc_from_full: %d" "$perc" "$perc_from_full"
2023-12-28 00:35:48 +00:00
log "full: %f, rate: %f" "$full" "$rate"
log " rate > 0 means charging, else discharging"
}
2023-11-19 01:49:58 +00:00
2023-07-13 00:40:52 +00:00
fmt_minutes() {
2023-12-28 01:11:51 +00:00
# args:
# 1: icon to render
# 2: string to show if charge/discharge time is indefinite
# 3: minutes to stable state (i.e. to full charge or full discharge)
# - we work in minutes instead of hours for precision: bash math is integer-only
2023-12-28 00:35:48 +00:00
log "charge/discharge time: %f min" "$3"
2023-07-21 22:51:24 +00:00
# args: <battery symbol> <text if ludicrous estimate> <estimated minutes to full/empty>
2023-12-28 17:35:33 +00:00
if [ -n "$3" ] && [ "$3" -lt 1440 ]; then
2023-07-21 22:51:24 +00:00
hr=$(($3 / 60))
2023-07-13 00:40:52 +00:00
hr_in_min=$(($hr * 60))
2023-07-21 22:51:24 +00:00
min=$(($3 - $hr_in_min))
2023-12-28 03:05:27 +00:00
printf "%s%s%d%s%02d%s" "$1" "$suffix_icon" "$hr" "$symbol_hr" "$min" "$symbol_min"
2023-12-28 17:35:33 +00:00
else
log "charge/discharge duration > 1d"
printf "%s%s%s" "$1" "$suffix_icon" "$2" # more than 1d
2023-07-13 00:40:52 +00:00
fi
}
2023-12-28 00:35:48 +00:00
pretty_output() {
2023-12-28 17:35:33 +00:00
if [ -n "$perc" ]; then
duration=""
if [ "$rate" -gt 0 ]; then
log "charging"
icon="$(render_icon chg $perc)"
duration="$(($full * 60 * $perc_from_full / (100 * $rate)))"
else
log "discharging"
icon="$(render_icon dis $perc)"
if [ "$rate" -lt 0 ]; then
duration="$(($full * 60 * $perc / (-100 * $rate)))"
fi
fi
2023-12-28 17:43:34 +00:00
fmt_minutes "$icon" "$perc$suffix_percent" "$duration"
2023-12-28 00:35:48 +00:00
fi
}
while [ "$#" -gt 0 ]; do
case "$1" in
"--debug")
shift
BATTERY_ESTIMATE_DEBUG=1
;;
2023-12-28 03:05:27 +00:00
"--icon-suffix")
shift
suffix_icon="$1"
shift
;;
"--hour-suffix")
shift
symbol_hr="$1"
shift
;;
"--minute-suffix")
shift
symbol_min="$1"
shift
;;
2023-12-28 17:43:34 +00:00
"--percent-suffix")
shift
suffix_percent="$1"
shift
;;
2023-12-28 00:35:48 +00:00
*)
usage
exit 1
;;
esac
done
try_all_paths
pretty_output