Running a Raspberry Pi 24/7: what a short power cut revealed about my system
My energy management system JG Energy runs around the clock on a Raspberry Pi 5 with an SSD. It controls the wallbox, the home battery and charge plans for two EVs. If the Pi fails, you notice in everyday life – at the latest when the car isn’t charged in the morning.
In early November there was a short power cut one morning. The Pi restarted on its own afterwards, and everything kept running. Still, the incident exposed four weak spots I hadn’t known about.
Step 1: was it really a power cut?
My first suspicion was a crash. A simple trick helps to tell the difference: compare the uptime of all devices. If the Pi, the Shellys and other devices all restarted in the same minute, it was the power. If only the Pi is back at zero, it was the Pi.
Shellys from generation 2 onwards report their uptime via the local API:
curl -s http://<shelly-ip>/rpc/Shelly.GetStatus | jq .sys.uptime
# → seconds since the last start
For the Pi itself, uptime -s is enough. In my case all start times matched within a few seconds: power cut.
Step 2: why were there no logs?
Next I wanted to check the system log for what happened before the restart. Result: nothing. The log started with the restart.
Yet I had already enabled the persistent journal earlier – with Storage=persistent in /etc/systemd/journald.conf. The problem: Raspberry Pi OS overrides this setting. It ships its own drop-in file:
/usr/lib/systemd/journald.conf.d/40-rpi-volatile-storage.conf
→ Storage=volatile
Files in journald.conf.d/ take precedence over the main file. So my setting had no effect, and the log only lived in RAM. It was gone after every restart – including exactly the part you most want to see after a crash: what happened just before.
This shows which setting actually applies:
systemd-analyze cat-config systemd/journald.conf
The fix is a drop-in of your own with a higher number, so it’s read last:
sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/99-persistent.conf <<'EOF'
[Journal]
Storage=persistent
SystemMaxUse=500M
EOF
sudo systemctl restart systemd-journald
sudo journalctl --flush
journalctl --list-boots shows whether it worked: after the next restart there should be several entries. journalctl -b -1 then gives you the log of the previous boot.
On an SSD this is no problem. On an SD card you should weigh it more carefully because of the write load.
Step 3: the lost startup message
JG Energy sends a Telegram message after every start. After the power cut, none arrived. The log said:
⚠️ Telegram error: getaddrinfo EAI_AGAIN api.telegram.org
EAI_AGAIN means name resolution is temporarily unavailable. After a power cut the Pi boots faster than the router and the internet connection. When JG Energy tried to send the message, there simply was no internet yet. The message was lost.
After=network-online.target in the systemd service doesn’t solve this: the Pi then has a network connection, but the router doesn’t have a connection to the outside world yet.
The solution is a queue. If a message fails because of a network error, it’s put aside and retried every minute:
- Retried: errors without a response (DNS, timeout) as well as HTTP 429 and 5xx.
- Not retried: other 4xx errors, e.g. invalid HTML. Those won’t get better on the tenth attempt either.
- A message is dropped after 30 minutes, and at most 50 are kept.
- If a message arrives more than 90 seconds late, it gets a note: “delayed, originally 09:23”.
- New messages join the back of the queue as long as it isn’t empty. That keeps the order intact.
function retryable(err) {
const status = err?.response?.status;
return !status || status === 429 || status >= 500; // no status = no response
}
Step 4: clean shutdown or crash?
The startup message now also answers the question I asked myself after the power cut:
🟢 JG Energy started
⚠️ The Pi restarted too (1 min ago)
⚠️ Last run did NOT shut down cleanly (last seen 09:22)
All it takes is two things:
- System uptime from
/proc/uptime: if it’s less than 5 minutes, the whole Pi was restarted, not just the program. - A farewell note: on an orderly shutdown (
SIGTERM) the program saves “shut down cleanly”. At startup the note is read and immediately reset to “not clean”. In addition, the program saves a timestamp every minute. If the note is missing at the next start, there was a crash or power cut – and the timestamp shows when the program was last alive.
Step 5: the hardware watchdog against hangs
A power cut is harmless because the Pi starts again on its own. A Pi that hangs is more dangerous: it’s switched on but no longer responds. Then nothing restarts.
The Raspberry Pi’s built-in hardware watchdog helps here. systemd has to “feed” it regularly. If that stops, the hardware restarts the Pi. The Pi’s watchdog allows at most about 15 seconds, so I use 14:
sudo mkdir -p /etc/systemd/system.conf.d
sudo tee /etc/systemd/system.conf.d/watchdog.conf <<'EOF'
[Manager]
RuntimeWatchdogSec=14s
EOF
sudo systemctl daemon-reexec
You can check it with:
systemctl show -p RuntimeWatchdogUSec # → 14s
dmesg | grep -i watchdog
The watchdog monitors the system, not the program. If only JG Energy crashes, the systemd service with Restart=always takes care of it.
Step 6: the devices must be safe without the server
The most important question for 24/7 operation isn’t how quickly the server is back. It’s: what do the devices do while it’s gone?
For the wallbox I solved this by making every lock the server sets expire on its own after two hours at most. If the Pi fails, the wallbox then charges like any ordinary wallbox. The car is full in the morning – just not with solar power.
The home battery has no such option. If the server fails while discharging is locked during surplus charging (the “stays off” setting), it stays locked. I estimated how often exactly this combination occurs and decided to accept it. What matters is knowing the gap exists.
Conclusion
A short power cut didn’t do any damage in my case. But it showed that without logs and without a startup message, I wouldn’t have known what had happened in a real emergency.
My checklist for any Pi that controls something important:
- Store the journal persistently – and check with
systemd-analyze cat-configthat the setting actually applies. - Buffer notifications instead of dropping them at the first network error.
- Report at startup whether the last run shut down cleanly.
- Enable the hardware watchdog.
- For every device you control, work out what it does when the server fails.