Skip to content

Repository files navigation

batmon

Battery health monitor & hardware flight recorder for Linux laptops.

batmon is a zero-dependency, low-overhead background daemon that continuously records power, thermal, and system telemetry to local SQLite databases.

It operates as a high-frequency flight recorder, capturing hardware metrics every second to preserve the exact state of the machine in the event of a crash or kernel panic, while simultaneously maintaining a permanent, downsampled historical log for tracking long-term component wear and battery degradation.


🎯 Architecture: Dual-Tier Monitoring

batmon captures telemetry using two distinct tiers:

                      ┌───────────────────────────────────────────────┐
                      │             batmon Daemon (Bun)               │
                      └───────┬───────────────────────────────┬───────┘
                              │ (Every 1 sec)                 │ (Every 60 sec)
                              ▼                               ▼
               ┌──────────────────────────────┐ ┌──────────────────────────────┐
               │    debug.db (Flight Log)     │ │  battery.db (Historical DB)  │
               ├──────────────────────────────┤ ├──────────────────────────────┤
               │ • 1s sample resolution       │ │ • 60s sample resolution      │
               │ • SQLite WAL + sync=NORMAL   │ │ • SQLite WAL + sync=NORMAL   │
               │ • Auto-pruned (last 6 hours) │ │ • Permanent wear records     │
               │ • Crash & panic forensics    │ │ • Cycle count & degradation  │
               └──────────────────────────────┘ └──────────────────────────────┘
  1. High-Frequency Flight Recorder (debug.db):
    Records every 1 second directly to SQLite using WAL mode (PRAGMA synchronous = NORMAL). Coalesced by the Linux kernel page cache, it consumes negligible power (<15 mW) while ensuring that during hard lockups, thermal throttling, or kernel panics, the crucial minutes leading up to the failure are safely preserved on disk for post-mortem forensics (with at most ~2–5s uncommitted in kernel page cache during sudden hard power cuts). Auto-prunes older records on a rolling window (default: 6 hours).

  2. Long-Term Historical Telemetry (battery.db):
    Records downsampled samples every 60 seconds. Tracks long-term battery degradation, design wear capacity, and software-integrated cycle count over months and years.


📊 What It Logs

Category Metric Source Description
Electrical & Power voltage_v sysfs (battery) Instantaneous battery rail voltage (V)
power_w sysfs (battery) Discharge / charge rate (Watts)
charge_pct sysfs (battery) Current state of charge (%)
energy_wh sysfs (battery) Remaining energy (Wh)
energy_full_wh sysfs (battery) Current full charge capacity (Wh)
energy_design_wh sysfs (battery) Factory nominal design capacity (Wh)
voltage_design_v sysfs (battery) Factory design voltage (V)
is_charging sysfs (battery) Charge state boolean
Thermal Environment cpu_temp_c sysfs (hwmon) CPU package / core temperature (e.g. AMD Tctl / Intel Package id) (°C)
gpu_temp_c sysfs (hwmon) GPU temperature (e.g. AMD edge / Intel package) (°C)
nvme_temp_c sysfs (hwmon) NVMe composite temperature (°C)
battery_temp_c sysfs (battery / hwmon) Battery sensor temperature (if present)
Clock & SoC Power cpu_freq_mhz sysfs (cpufreq) / /proc Instantaneous CPU clock frequency (MHz)
gpu_power_w sysfs (hwmon) AMD APU / GPU package power (PPT via amdgpu) (Watts)
gpu_pct sysfs (DRM) GPU compute / shader utilization (%)
System Load cpu_pct /proc/stat Global CPU utilization (%)
mem_pct /proc/meminfo Global Memory utilization (%)
load1 /proc/loadavg 1-minute system load average
top_processes /proc/[pid]/stat Top 5 aggregated process groups by 1s CPU delta (JSON)
Health & Wear health_pct sysfs Full charge capacity vs design capacity (%)
cycle_count sysfs Hardware cycle count (if reported by BMS)
estimated_cycle_count Integrator Calculated cycle count via energy throughput ($\Delta\text{Wh} / \text{Design}$)
Runtime Estimates time_to_empty_s UPower D-Bus Smoothed discharge runtime estimate (seconds)
time_to_full_s UPower D-Bus Smoothed charge completion estimate (seconds)
  • Auto-detects energy_* (µWh) vs charge_* (µAh) battery drivers.
  • Low-Overhead Native Reads: All CPU, memory, clock, GPU, thermal, and process metrics are gathered directly via Linux kernel VFS interfaces (/proc and /sys) and standard POSIX process accounting (~5–8 ms execution per sample cycle) with zero child processes or external daemons. See empirical evaluations on Kernel VFS vs. Glances and Sysfs Hwmon vs. lm-sensors for detailed benchmark results.
  • Automatic Migrations: Database schema updates and column additions are handled seamlessly and automatically on startup using SQLite's native user_version tracking with zero manual migration steps required.

🔍 Post-Mortem Forensics & SQL Recipes

1. Inspect the last 30 seconds before a crash

sqlite3 ~/.local/share/batmon/debug.db "
SELECT ts, power_w, voltage_v, cpu_freq_mhz, cpu_temp_c, gpu_power_w, cpu_pct, top_processes
FROM samples
ORDER BY id DESC
LIMIT 30;"

2. Check long-term battery degradation & wear

sqlite3 ~/.local/share/batmon/battery.db "
SELECT ts, charge_pct, health_pct, cycle_count, estimated_cycle_count, energy_full_wh, energy_design_wh
FROM samples
ORDER BY id DESC
LIMIT 10;"

3. Identify top power-hog process groups

sqlite3 ~/.local/share/batmon/debug.db "
SELECT ts, power_w, cpu_temp_c, top_processes
FROM samples
WHERE power_w > 30.0
ORDER BY id DESC
LIMIT 5;"

🔔 Desktop Notifications & Alerts

batmon features a stateful alerting engine with deadband hysteresis, debouncing, and priority escalation to prevent notification storms from flapping sensors:

  • High Battery Temp Warning: Alert when battery temp $\ge 45^\circ\text{C}$ (Critical at $50^\circ\text{C}$ with contextual cooling advice; re-arms below $42^\circ\text{C}$ / $47^\circ\text{C}$).
  • Charging While Hot (Heat-Soak): Alert when charging while CPU $\ge 85^\circ\text{C}$ (re-arms below $80^\circ\text{C}$).
  • Charge Limits: Reminders to unplug at $\ge 80%$ (re-arms below $75%$) and plug in at $\le 20%$ (Critical at $\le 10%$ suppresses normal low alert; re-arms above $25%$).
  • Over-Voltage Charging: Alert when charging voltage exceeds 15% above design voltage (re-arms at or below 10% above design voltage).
  • Battery Health Degradation: Warning when full capacity drops below $80%$ of factory design (re-arms above $82%$).

Note: The current alert rules focus on battery protection, because by the time the voltage or power really drops, the system will be shutting down anyway. The idea is to prevent these issues from happening in the first place, not to detect them after the fact. The flight recorder is there to capture the data in case something does happen.


🛠️ Requirements

  • Linux with systemd (Fedora, Ubuntu, Debian, Arch, etc.)
  • Bun runtime ($\ge 1.3$)
  • libnotify / notify-send (optional, for desktop notifications):
    sudo dnf install libnotify     # Fedora/RHEL
    sudo apt install libnotify-bin # Ubuntu/Debian
  • sqlite3 CLI (optional, for querying databases): sudo dnf install sqlite

🚀 Installation

git clone https://github.com/InvictusNavarchus/batmon.git
cd batmon
./install.sh
# or using bun:
bun run install-service

The installer will:

  1. Copy the application to ~/.local/share/batmon/src/.
  2. Configure and start a systemd user service (batmon.service).
  3. Run an initial test verification.

Managing the Service

# Check service status
systemctl --user status batmon.service

# View live logs
journalctl --user -u batmon.service -f

# Run a one-off diagnostic sample
bun run src/index.ts --oneshot

🧪 Development & Testing

Run unit tests and typechecks using Bun:

# Run test suite
bun test

# Run typechecker
bun run typecheck

🗑️ Uninstallation

./uninstall.sh
# or using bun:
bun run uninstall-service

(Databases in ~/.local/share/batmon/ are preserved upon uninstall).

Limitations

  • Battery cell-level data (individual cell voltages, internal impedance, BMS balancing status) is not available through the Linux power_supply sysfs interface and cannot be collected.
  • VRM rail voltages and transient events below ~1 s are not exposed by the kernel on most laptop hardware. The 1-second flight recorder can catch sustained voltage sag but not microsecond-scale transients.
  • The battery_temp_c sensor is absent on many laptops. When unavailable, battery thermal protection relies on ambient correlation with CPU/GPU temperatures.
  • mem_pct and load1 are recorded for forensic completeness but are rarely primary indicators of hardware failure.

About

Battery health monitor & high-frequency hardware flight recorder for Linux laptops.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages