Tutorial: Sizing a Raspberry Pi UPS and Wiring the Automatic Shutdown

Contents
A UPS for a Raspberry Pi is bought by one number and judged by another. The number on the box is the cell capacity. The number that matters is how long the machine keeps running – and between the two sit three deductions that together take about a third.
What follows is the calculation in the order it has to be done, and the part that is not a calculation at all: the shutdown has to happen while there is still energy left, because a pack that empties itself takes the file system with it.

What the Setup Actually Draws
Data sheets describe the power supply, not the consumption. The official 27-watt supply for the Raspberry Pi 5 says nothing about the machine; it says what the machine may draw at peak with a full USB load.
The real figure is measurable on the board itself. Both the Pi 4 and the Pi 5 carry a power management chip whose rails can be read out, and the sum over all rails is the total draw.
vcgencmd pmic_read_adc | awk '
/_A current/ { split($1, n, "_"); a[n[1]] = $2 + 0 }
/_V volt/ { split($1, n, "_"); v[n[1]] = $2 + 0 }
END { for (r in a) s += a[r] * v[r]; printf "%.2f W\n", s }'
Measured that way, a Pi 5 sits at roughly 2.7 watts idle and reaches about 9 watts with all four cores busy. An NVMe drive under load adds one and a half to two and a half watts, the active cooler about half a watt, and a USB hard disk two to three. The realistic planning figure for a small home server is therefore somewhere between six and twelve watts, and both ends of that range are worth calculating.
One measurement is not enough, because the interesting moment is not the average. A power cut during a backup finds the machine at its peak, and the runtime that matters is the one under load.
From Milliamp-Hours to Watt-Hours
Cells are labelled in milliamp-hours, which is a charge and not an energy. Multiplying by the nominal cell voltage turns it into something comparable.
Wh = mAh × V / 1000
3400 mAh × 3.7 V / 1000 = 12.58 Wh per cell
two cells in parallel = 25.2 Wh
The nominal 3.7 volts is the average across the discharge curve, not the full-charge voltage of 4.2. Using 4.2 in the formula inflates the result by a good ten per cent and is the most common reason a calculation ends up too optimistic.
A comparison worth keeping in mind: a power bank advertised as 20 000 mAh is measured at cell level, not at the USB port. At 3.7 volts that is 74 watt-hours, which after conversion to 5 volts becomes roughly 55 – and that is the number the marketing figure hides.
The Part of the Pack That Never Becomes Runtime
Three deductions stand between the cells and the machine, and each has a different cause.
The first is the converter. Cells deliver between 4.2 and 3.0 volts, the Pi needs a stable 5.1. The boost converter that bridges this runs at about 88 per cent under a typical load, which costs three watt-hours of the 25.2. Cheap modules drop below 80 per cent at low load, which is exactly the load an idling Pi produces.
The second is the voltage floor. Lithium cells are cut off at around three volts per cell, and the energy below that line stays in the pack. That is not waste but protection: discharging further ages the cell disproportionately and, below 2.5 volts, damages it permanently. About five per cent of the pack sits below that line.
The third is the one that is chosen rather than given. A shutdown takes ten to thirty seconds, and it has to start while the converter is still delivering a stable five volts. A reserve of fifteen per cent of the net energy leaves room for that, plus room for a pack that has aged and for a second power cut minutes after the first.
What remains of 25.2 watt-hours is 17.8. The runtimes follow directly.
| Load | Typical situation | Runtime from 17.8 Wh |
|---|---|---|
| 6 W | Pi 5, idle, SD card | 2 h 58 min |
| 9 W | Pi 5 with NVMe, moderate load | 1 h 59 min |
| 12 W | All cores busy, disk and cooler | 1 h 29 min |
Triggering the Shutdown Before the Cut
Every UPS worth the name signals the loss of mains power somehow. Two mechanisms cover almost all the boards on the market, and the simpler one needs no software at all.
A HAT that pulls a GPIO pin low can trigger the shutdown through a device tree overlay. One line in the boot configuration is the whole implementation.
# /boot/firmware/config.txt
dtoverlay=gpio-shutdown,gpio_pin=17,active_low=1,gpio_pull=up
The advantage is that this works without a running service and even during boot. The disadvantage is that it shuts down immediately, which is wrong for a power cut lasting four seconds. A short delay makes the difference between a considered reaction and a nightly restart.
#!/bin/bash
# /usr/local/bin/usv-wacht.sh - waits for a lasting loss of mains power
while gpiomon --num-events=1 --falling-edge gpiochip0 17 >/dev/null; do
sleep 60
if gpioget gpiochip0 17 | grep -q '^0$'; then
logger -t usv "mains gone for 60 s - shutting down"
/sbin/shutdown -h now
fi
done
# /etc/systemd/system/usv-wacht.service
[Unit]
Description=UPS watch
After=multi-user.target
[Service]
ExecStart=/usr/local/bin/usv-wacht.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
The second mechanism is a fuel gauge over I2C – a MAX17048 or an INA219 sits on most better boards and reports the state of charge as a percentage. That allows the trigger to depend on the pack rather than on the clock, which is the more honest criterion: shut down below twenty per cent, regardless of how long the power has been gone.
Whichever route is chosen, one setting belongs with it. A machine that shuts down during a power cut has to come back on its own when the power returns, and on the Pi 5 that is a bootloader option rather than an operating system one.
sudo rpi-eeprom-config --edit
# POWER_OFF_ON_HALT=1
# WAKE_ON_GPIO=0
# PSU_MAX_CURRENT=5000
The Test That Has to Happen on Purpose
A UPS that has never been tested is an assumption. The test is unspectacular and takes an afternoon: put the machine under the load it will actually see, pull the mains plug, and note two times – when the shutdown started and when the pack gave out.
Afterwards the log of the previous boot holds the evidence. A clean shutdown ends with a stop message for the file system; an abrupt end shows nothing at all, which is itself the finding.
journalctl -b -1 -n 30 --no-pager
Two results are common and both are useful. If the shutdown started but the pack died before it finished, the reserve is too small. If the pack still had charge minutes after the machine was down, the reserve is generous – which is a good place to be, and worth knowing rather than assuming.
Repeating this once a year costs an hour and catches the failure mode that has no other symptom: a pack that has quietly lost half its capacity while sitting fully charged.
What Two Years Change
Lithium cells lose capacity in two ways, and only one of them is caused by use. Three to five hundred full cycles bring a cell to roughly eighty per cent of its original capacity, which for a UPS that discharges a handful of times a year is irrelevant.
The other way is time, and it is the one that applies here. A cell held permanently at full charge and at the temperature inside a closed case ages measurably faster than the same cell at storage charge. After two years in a warm cupboard, twenty to thirty per cent capacity loss is normal rather than a defect.
Two consequences follow. Boards that charge to 4.1 volts instead of 4.2 give up around ten per cent of nominal capacity and roughly double the calendar lifetime, which is a good trade for a device that spends its life waiting. And the sizing at the start is better done with the pack it will be in two years, not the one out of the box – a reserve chosen so that eighty per cent of the pack still carries the shutdown.