feat(battery): low-battery notifications at the bar's 25/10% thresholds (item 13 slice)
All checks were successful
Check / eval (push) Successful in 3m4s
All checks were successful
Check / eval (push) Successful in 3m4s
The bar colored the battery at 25/10% but nothing notified. New shellcheck-gated watcher (pkgs/nomarchy-battery-notify, overlay) polls the same sysfs the bar reads — type=Battery, scope!=Device — and fires one toast per downward crossing (normal at 25%, critical at 10%; swaync keeps critical up until dismissed), re-armed by charging. Self-gates on battery presence (the powerprofile pattern), so desktops get a silent no-op. HM user unit behind nomarchy.batteryNotify.enable (default on) with libnotify on the unit PATH; notify-send resolves from PATH so the VM check can shim it. poweralertd rejected: its UPower thresholds (20/5) wouldn't match the bar, and it toasts every plug/unplug. Verified: V0 (flake check, bash -n); V1 (template-home builds, unit in the generation); V2 GREEN (new checks.battery-notify, test_power fake battery: self-gate, silence at 80%, one toast per crossing, critical urgency, charging re-arms). Remains: V3 — real swaync toast on a draining laptop (HARDWARE-QUEUE). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
12
pkgs/nomarchy-battery-notify/default.nix
Normal file
12
pkgs/nomarchy-battery-notify/default.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
# Low-battery notification watcher (nomarchy.batteryNotify). A package
|
||||
# (not an inline script) so the VM check can exercise the crossing logic
|
||||
# on a minimal node against a test_power fake battery — same reasoning
|
||||
# as nomarchy-doctor. libnotify is deliberately NOT a runtimeInput: the
|
||||
# user unit puts it on PATH; the check shims notify-send instead.
|
||||
{ writeShellApplication, coreutils }:
|
||||
|
||||
writeShellApplication {
|
||||
name = "nomarchy-battery-notify";
|
||||
runtimeInputs = [ coreutils ];
|
||||
text = builtins.readFile ./nomarchy-battery-notify.sh;
|
||||
}
|
||||
58
pkgs/nomarchy-battery-notify/nomarchy-battery-notify.sh
Normal file
58
pkgs/nomarchy-battery-notify/nomarchy-battery-notify.sh
Normal file
@@ -0,0 +1,58 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user