The stuff I do

Using a systemd timer to monitor my laptop's battery

- 641 words -

← Posts

I've been using i3 as my window manager for the past 7 years. It's great and you should check it out! However, one issue I have is that by default I don't get an obvious notification when my battery is low. My personal laptop is getting old and the battery significantly drains when it is put to sleep. So recently it happened several times that I woke it up, didn't check my battery, and had it die a few minutes later because it was on super low battery.

So I created a simple bash script which checks the battery level and uses notify-send to display a desktop notification to remind me to charge the computer. The question was how to run it:

So I finally looked into systemd timers, which I've been meaning to do for a long time but I was worried it would add too much complexity to my dotfiles system.

I was wrong.


The solution 🔗

To set up a systemd service at the user level you need 2 files:

  1. monitor_battery.service which defines how the service runs, that's not much more than pointing to the path of the script (Here ~/.bin/monitor-battery):
[Unit]
Description=Low battery popup notification

[Service]
Type=oneshot
ExecStart=%h/.bin/monitor-battery

# notify-send requires a running D-Bus session

Environment=DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus
  1. monitor_battery.timer which defines when the service runs, here 1 minute after boot and then every 5 minutes after that:
[Unit]
Description=Check battery level every 5 minutes

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target

After putting these files in ~/.config/systemd/ I just have to run 2 commands once to enable and start the service:

systemctl --user enable --now monitor_battery.timer
systemctl --user start monitor_battery.timer

As they are idempotent I can just add them to the script which sets up my dotfiles (which I run once in a while when I change my configs) and that's it!

Result 🔗

The good part is that now this script is managed like a regular systemd unit. So

  1. I can use systemctl to start, stop, check the status of the service

  2. Handling the logs is super easy:

    • I don't have to handle inconvenient shell redirections in my crontab (stuff like >> /var/log/monitor.log 2>&1)
    • Every echo in my script is sent to the logs automatically
    • By default systemd logs the startup and end times of the script so I don't need to pollute my script with additional logging
    • I can use journalctl --user -u monitor_battery.service to access the logs without having to find back the log file
    Mar 27 11:42:05 hostname systemd[3972]: Starting monitor_battery.service - Low battery popup notification...
    Mar 27 11:42:05 hostname monitor-battery[93724]: Fri Mar 27 11:42:05 AM CET 2026 level='95' status='Discharging' alerted='0'
    Mar 27 11:42:05 hostname systemd[3972]: Finished monitor_battery.service - Low battery popup notification.
    Mar 27 11:47:16 hostname systemd[3972]: Starting monitor_battery.service - Low battery popup notification...
    Mar 27 11:47:16 hostname monitor-battery[97345]: Fri Mar 27 11:47:16 AM CET 2026 level='94' status='Discharging' alerted='0'
    Mar 27 11:47:16 hostname systemd[3972]: Finished monitor_battery.service - Low battery popup notification.
    

    Note how I should remove the echo "$(date) ... from the monitor-battery script to avoid duplicating the date

Moralité: Tailoring your tools to your needs is a good way to learn new stuff!

Resources 🔗

← Posts


Related posts

Posts in the same category: [linux]


Comments


Back to top