Linux – using systemd timers instead of cron

arch linuxlinuxsystemdsystemd-timer

I am on Arch Linux where I am trying to create a systemd timer as a cron alternative for hibernating my laptop on low battery. So I wrote these three files:

/etc/systemd/system/battery.service

[Unit]
Description=Preko skripte preveri stanje baterije in hibernira v kolikor je stanje prenizko

[Service]
Type=oneshot
ExecStart=/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript
User=nobody
Group=systemd-journal

/etc/systemd/system/battery.timer

[Unit]
Description=Periodical checking of battery status every two minutes

[Timer]
OnUnitActiveSec=2min 

[Install]
WantedBy=timers.target

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

#!/bin/sh
/usr/bin/acpi -b | /usr/bin/awk -F'[,:%]' '{print $2, $3}' | (
        read -r status capacity
        if [ "$status" = Discharging ] && [ "$capacity" -lt 50 ]; then
                /usr/bin/systemctl hibernate
        fi                                                                                                                
)    

And then to enable timer I executed:

sudo systemctl enable battery.timer
sudo systemctl start battery.timer

And somehow it isn't working. Script works on its own. This means that if I execute command below, my computer hibernates just fine.

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

ADD1:

After enabling and starting timer I ran some checks and this is what I get:

[ziga@ziga-laptop ~]$ systemctl list-timers
NEXT                          LEFT       LAST                          PASSED    UNIT                         ACTIVATES
n/a                           n/a        n/a                           n/a       battery.timer                battery.serv
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   logrotate.timer              logrotate.se
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   shadow.timer                 shadow.servi
Tue 2016-06-28 00:00:00 CEST  42min left Mon 2016-06-27 00:01:54 CEST  23h ago   updatedb.timer               updatedb.ser
Tue 2016-06-28 22:53:58 CEST  23h left   Mon 2016-06-27 22:53:58 CEST  23min ago systemd-tmpfiles-clean.timer systemd-tmpf

and

[ziga@ziga-laptop ~]$ systemctl | grep battery
battery.timer  loaded active elapsed   Periodical checking of battery status every two minutes

ADD2:

After applying solution from Alexander T my timer starts (check the code below) but script doesn't hibernate my laptop while it hibernates it if I execute it directly.

[ziga@ziga-laptop ~]$ systemctl list-timers
NEXT                          LEFT          LAST                          PASSED       UNIT                         ACTIVATES
Tue 2016-06-28 19:17:30 CEST  1min 43s left Tue 2016-06-28 19:15:30 CEST  16s ago      battery.timer                battery.service

Best Answer

An answer to this question is to swap User=nobody not with User=ziga but with User=root in /etc/systemd/system/battery.service. Somehow even if user ziga has all the privileges of using sudo command it can't execute systemctl hibernate inside of the bash script. I really don't know why this happens. So the working files are as follows:

/etc/systemd/system/battery.service

[Unit]
Description=Preko skripte preveri stanje baterije in hibernira v kolikor je stanje prenizko

[Service]
Type=oneshot
ExecStart=/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript
User=root
Group=systemd-journal

/etc/systemd/system/battery.timer

[Unit]
Description=Periodical checking of battery status every two minutes

[Timer]
OnBootSec=2min
OnUnitActiveSec=2min 

[Install]
WantedBy=battery.service

/home/ziga/Dropbox/workspace/operacijski/archlinux/hibernate/hibernatescript

#!/bin/sh
/usr/bin/acpi -b | /usr/bin/awk -F'[,:%]' '{print $2, $3}' | (
        read -r status capacity
        if [ "$status" = Discharging ] && [ "$capacity" -lt 7 ]; then
                /usr/bin/systemctl hibernate
        fi
)

I tried it and it allso works with User=ziga or User=nobody but we need to change /usr/bin/systemctl hibernate into sudo /usr/bin/systemctl hibernate in the last script. So it looks like User variable somehow doesn't even matter... Oh and you can as well remove absolute names from the last script and change first line from #!/bin/sh to #!/bin/bash. I also changed WantedBy=timers.target to WantedBy=battery.service in /etc/systemd/system/battery.timer.

There you go. The best cron alternative to hibernate laptops on low battery. =)

Related Question