# Low-battery notifications — the session-side complement to the bar's # battery colors: Waybar paints the module @warn at 25% and @bad at 10% # (waybar.nix battery.states) but nothing *notified*. This watcher polls # the same sysfs state the bar reads and fires exactly one notification # per downward crossing — normal at 25%, critical at 10% (swaync keeps # critical toasts up until dismissed) — re-arming once the charger lands. # # notify-send is resolved from PATH on purpose (not a runtimeInput): the # unit (battery-notify.nix) provides libnotify; the VM check shims it to # capture the calls. # # usage: nomarchy-battery-notify [poll-interval-seconds] interval="${1:-30}" warn=25 crit=10 # System batteries only: type Battery, and not scope=Device (how # peripheral batteries — mice, headsets — report). Name-agnostic on # purpose: BAT0, dual-battery BAT0+BAT1, CMB0, test_battery all match. batteries() { local d for d in /sys/class/power_supply/*/; do [ "$(cat "$d/type" 2>/dev/null)" = Battery ] || continue [ "$(cat "$d/scope" 2>/dev/null || echo System)" = Device ] && continue printf '%s\n' "$d" done } # Self-gate: no battery, not a laptop — a clean no-op on desktops. [ -n "$(batteries)" ] || exit 0 state=ok # ok → warn → crit, one notification per downward crossing while :; do sum=0 n=0 discharging= while IFS= read -r d; do cap=$(cat "$d/capacity" 2>/dev/null) || continue sum=$((sum + cap)); n=$((n + 1)) [ "$(cat "$d/status" 2>/dev/null)" = Discharging ] && discharging=1 done < <(batteries) if [ "$n" -gt 0 ] && [ -n "$discharging" ]; then cap=$((sum / n)) if [ "$cap" -le "$crit" ] && [ "$state" != crit ]; then notify-send -u critical -a Nomarchy "Battery critical: ${cap}%" \ "Plug in now." state=crit elif [ "$cap" -le "$warn" ] && [ "$state" = ok ]; then notify-send -u normal -a Nomarchy "Battery low: ${cap}%" \ "Consider plugging in." state=warn fi else # On the charger (or nothing readable): re-arm for the next drain. state=ok fi sleep "$interval" done