feat(doctor): battery health readout (#80)
Some checks failed
Check / eval (push) Has been cancelled
Some checks failed
Check / eval (push) Has been cancelled
Report-only cycle_count + retained capacity (charge_* or energy_*) as % of design on system batteries; soft warn below 70% of design; skip when attrs missing. NOMARCHY_POWER_SUPPLY_ROOT for the checks.doctor fixture (test_power has no cycle/design attrs). Verified: V2 — nix flake check --no-build; checks.doctor green (fake BAT0 cycles/% + Device-scope ignore); local BAT0 smoke (energy_*).
This commit is contained in:
@@ -263,6 +263,61 @@ if [ "$bat_seen" -eq 1 ] && [ "$bat_limited" -eq 0 ]; then
|
||||
skip "battery charge limit (none set — charges to 100%)"
|
||||
fi
|
||||
|
||||
# ── battery health (report-only, BACKLOG #80) ────────────────────────
|
||||
# cycle_count + retained capacity (charge_* µAh or energy_* µWh). Same
|
||||
# system-battery filter as charge-limit/notify. Self-gates when no
|
||||
# battery or the firmware omits the attrs (desktops, bare VMs). Override
|
||||
# the sysfs root with NOMARCHY_POWER_SUPPLY_ROOT for the checks.doctor
|
||||
# fixture (test_power has no cycle/design attrs).
|
||||
ps_root="${NOMARCHY_POWER_SUPPLY_ROOT:-/sys/class/power_supply}"
|
||||
bat_health_seen=0
|
||||
for bat in "$ps_root"/*/; do
|
||||
[ -d "$bat" ] || continue
|
||||
[ "$(cat "$bat/type" 2>/dev/null)" = Battery ] || continue
|
||||
[ "$(cat "$bat/scope" 2>/dev/null || echo System)" = Device ] && continue
|
||||
name=$(basename "$bat")
|
||||
|
||||
cycles=$(cat "$bat/cycle_count" 2>/dev/null || true)
|
||||
case "$cycles" in ''|*[!0-9]*) cycles= ;; esac
|
||||
# Some firmwares export 0 forever — treat as unknown, not "brand new".
|
||||
if [ -n "$cycles" ] && [ "$cycles" -eq 0 ]; then cycles=; fi
|
||||
|
||||
full=""; design=""
|
||||
if [ -r "$bat/charge_full" ] && [ -r "$bat/charge_full_design" ]; then
|
||||
full=$(cat "$bat/charge_full" 2>/dev/null || true)
|
||||
design=$(cat "$bat/charge_full_design" 2>/dev/null || true)
|
||||
elif [ -r "$bat/energy_full" ] && [ -r "$bat/energy_full_design" ]; then
|
||||
full=$(cat "$bat/energy_full" 2>/dev/null || true)
|
||||
design=$(cat "$bat/energy_full_design" 2>/dev/null || true)
|
||||
fi
|
||||
case "$full" in ''|*[!0-9]*) full= ;; esac
|
||||
case "$design" in ''|*[!0-9]*) design= ;; esac
|
||||
pct=""
|
||||
if [ -n "$full" ] && [ -n "$design" ] && [ "$design" -gt 0 ]; then
|
||||
pct=$(( full * 100 / design ))
|
||||
fi
|
||||
|
||||
[ -n "$cycles" ] || [ -n "$pct" ] || continue
|
||||
bat_health_seen=1
|
||||
|
||||
detail=""
|
||||
[ -n "$cycles" ] && detail="${cycles} cycles"
|
||||
if [ -n "$pct" ]; then
|
||||
[ -n "$detail" ] && detail="$detail, "
|
||||
detail="${detail}${pct}% of design capacity"
|
||||
fi
|
||||
# Soft warn only — wear isn't a doctor "fix", just a heads-up.
|
||||
if [ -n "$pct" ] && [ "$pct" -lt 70 ]; then
|
||||
warn "$name health: $detail" \
|
||||
"battery wear is normal over years — replace when runtime suffers"
|
||||
else
|
||||
ok "$name health: $detail"
|
||||
fi
|
||||
done
|
||||
if [ "$bat_health_seen" -eq 0 ]; then
|
||||
skip "battery health (no system battery / no cycle or design capacity attrs)"
|
||||
fi
|
||||
|
||||
# ── hibernate / sleep (BACKLOG #76) ──────────────────────────────────
|
||||
# Read-only: is there a working hibernate path? zram is RAM-only and can't
|
||||
# hold a resume image, so hibernation needs a disk swap (partition or file)
|
||||
|
||||
Reference in New Issue
Block a user