How to actually measure your laptop’s battery endurance
You charge your laptop to 100%. The applet says “9 hours
remaining”. You sit down to work and the thing dies in 4. Sound
familiar?
There’s a simple reason: the number the firmware (or your DE’s
battery applet) shows at full charge is a projection based on the
instantaneous power draw at that very second, or on some generic
OEM spec figure. If it samples while the laptop is idling with the
screen off, you get 14 hours. If it samples while you’re compiling
or watching video, you get 3. Neither one is what you actually get
across a typical day.
What you actually need
To know for real how long your battery lasts, you need a
measurement of the average across your real usage - over weeks,
not seconds. You need to exclude time when the charger was plugged
in, because that doesn’t count toward single-charge endurance.
In other words, you need something that:
- Records the battery % every time the laptop sleeps, wakes,
boots, shuts down - Records when you plug the charger in and out
- Distinguishes awake on battery from on the charger
- Computes a realistic average draw using only the
awake-on-battery segments, then projects that out to a full
charge
batrun
A small tool for exactly this: batrun. It’s written in
C for Linux and lives in three hooks:
- a
systemd-sleepscript for sleep / resume - a
systemdoneshot service for boot / shutdown - a
udevrule for AC plug / unplug
Each hook invokes batrun event <type>, which reads
/sys/class/power_supply/ and inserts one row into a SQLite
database. No daemon, no polling, nothing eats CPU or RAM between
events. Any user on the system can read the data and ask “how long
does my battery actually last?”.
- Project: GitHub - LinuxRenaissance/batrun: batrun — battery intelligence, zero batshit · GitHub
- Latest release: Release batrun 0.5 · LinuxRenaissance/batrun · GitHub
Install
Grab the .deb from the releases page (tested on Debian 13, works
on Ubuntu / Mint / other Debian derivatives):
sudo dpkg -i batrun_*.deb
That’s it. The systemd service is enabled and started right away,
the hooks are live, data starts accumulating. No configuration.
What you get
Current state (batrun status):
batrun status -- 2026-05-19 17:01
================================================
Battery: 59% (34.89 Wh / 58.79 Wh)
Status: Discharging
Health: 103.1% of design (57.00 Wh design)
Cycle count: 0
AC adapter: not connected
Right now
Instant draw: 7.89 W
Remaining (instant): 4h 25m
Historical (last 30 days)
Awake-on-battery segments: 14
Average draw: 6.42 W
Projected at 100%: 9h 09m
Remaining at avg: 5h 25m <-- batrun estimate
Two estimates side by side:
- Instant - derived from the current
power_nowreading.
Swings with load. Answers “if I keep doing exactly what I’m
doing right now, how long do I have?”. - Historical - derived from the average draw across the last
30 days of your actual usage. Reflects how you use the
laptop, not what happens to be open at this instant.
Periodic report (batrun report):
batrun report # last 30 days (default)
batrun report --last 7d # last week
batrun report --last 6m # last six months
batrun report --month 2026-05 # a specific calendar month
batrun report --year 2025 # full calendar year
batrun report --all # everything in the database
batrun report --bare # single number only (for status bars)
The report shows total awake-on-battery time, total energy drained,
average draw, projected runtime at 100%, and battery health (current
full vs design capacity, cycle count).
Status bar integration
batrun report --bare prints a single line with the projected
full-charge runtime (e.g. 9h 36m), or - if there is not enough
data yet. It is designed to be polled by status bars and panel widgets.
waybar — add to ~/.config/waybar/config:
"custom/battery-life": {
"exec": "batrun report --bare",
"interval": 3600,
"format": "🔋 {}"
}
KDE Plasma — use a Command Output widget with the command
batrun report --bare and a refresh interval of 3600 seconds.
Hyprland / swaybar / i3bar — call batrun report --bare from
your bar script.
Raw data
The database lives at /var/lib/batrun/batrun.db, world-readable.
You can poke it directly with sqlite3:
sqlite3 /var/lib/batrun/batrun.db \
"SELECT datetime(ts,'unixepoch','localtime'), event_type,
battery_pct, ac_online
FROM events ORDER BY id DESC LIMIT 20;"
The schema is a single events table. All aggregation happens at
query time, nothing is precomputed - so when the analysis logic
needs to change someday, no migration of existing rows is required.
Realistic timeline
- Day 0 (right after install): you get a first estimate within
minutes. batrun folds the current on-battery session into the
calculation as soon as it is 10 minutes old, so you don’t have to
wait for a full sleep/wake cycle to see any number at all. - Day 2-3: the estimate stabilises as more completed segments
accumulate. It’ll wobble a bit depending on usage patterns. - One week in: the number genuinely reflects how you use your
laptop. - One month and beyond: you can track battery aging over time.
Comparebatrun report --month 2026-05with
batrun report --month 2027-05to see how much health you lost
in a year.
Why this beats the OEM number
Your OEM promises something like “up to 10 hours”. That’s
marketing - measured on a low-brightness display, idle desktop,
Wi-Fi off. You have no idea how that maps to your usage.
batrun measures your laptop in your hands. The number it
gives you is the number you actually care about.
Links
- Project: GitHub - LinuxRenaissance/batrun: batrun — battery intelligence, zero batshit · GitHub
- Releases /
.debdownload: Release batrun 0.5 · LinuxRenaissance/batrun · GitHub - License: BSD-2-Clause
Free software, pull requests welcome.