How to start realtime systemd timer services as a crontab replacement on the Raspberry Pi

If you are using crontab then you are familiar with starting actions depending on the date or time.

I have posted earlier why I stopped using crontab and have replaced it with the systemd command especially for jobs that should start at boot and that must restart automatically in case of a crash.

But just like crontab, systemd also provides the ability to schedule tasks at fixed times and dates.

In this article, I would like to show you how to apply the chronometric logic to the systemd command and to start timed actions like e.g. on the hour every hour/day/week/month or even on specific dates at a specific time.

I will focus on the commands and options that you would typically use for a digital picture frame application and spare you every detail and option so that you can quickly implement what you are looking for.

The simple way to schedule intervals in systemd without a timer

I want to start with an example where you don’t actually need a separate systemd timer.

If you have e.g. a Python script which sends a status message every ten minutes, there is no need for a timer. Just add these lines in your [Service] part of your .service script.

Restart=always
RestartSec=600

The number in RestartSec specifies in seconds how long to wait until a restart is triggered after the script has been executed. This syntax is useful when it really doesn’t matter if the message is sent at 0:10, 0:20, 0:30, etc. but just with an interval of 10 minutes, whenever it starts after boot.

Using realtime timers

The situation is different should you want a task scheduling at a specific time, like the chime of the hour bell.

In this case, you set up your systemd .service file as you normally would AND add a timer counterpart with the same name to it. The .timer file activates and controls the .service file.

The systemd command knows two types of timers: relative (called “monotonic”) and absolute (called “realtime”) timers.

Relative timers are defined by the time of another event like e.g. an event happening relative to the boot time (e.g. 10 minutes after boot).

Much more often, however, are realtime use cases for scheduling in “absolute” terms. This is similar to crontab.

To create a timer type

sudo nano /etc/systemd/system/name-of-your-timer.timer

It is vital that this file resides in the same directory and has the same name as your corresponding .service file.

The structure of a timer file is very similar to that of a service file but instead of a Service unit, there is the timer unit.

[Unit]
Description=Run my script every hour

[Timer]
OnCalendar=hourly

[Install]
WantedBy=timers.target

Under [Unit], you give a name that would help you recognise your timer in an overview list of timer files.

[Timer] has the following options that is important in our case:

OnCalendar=hourly

Specifying “hourly” means that the task is triggered each hour at :00.

  • daily triggers at 00:00:00.
  • weekly on Monday at 00:00:00
  • monthly will be executed on the first day of each month at 00:00:00

But it gets much better and the advantage compared to crontab is that your timer encoding is written in plain English and you don’t need a crontab ruler to translate.

There are other options like AccuracySec= but the default is one minute and that shall be fine for digital picture frames.

Timer syntax logic

The OnCalendar event uses the following syntax:

OnCalendar=DayOfWeek Year-Month-Day Hour:Minute:Second

An asterisk can be used to specify any value (-5-1).

Commas may be used to list possible values (e.g. Mon, Wed).

Two values separated by .. indicate a contiguous range (e.g. Mo..Fr).

To run a service at different times, OnCalendar can be specified more than once, like

 OnCalendar=Mon..Fri 07:00
 OnCalendar=Sat,Sun 09:00

To read more about the timer syntax, I recommend this page.

OnCalendar systemd timer examples

If you want to trigger a task every Friday at 18h, just say

OnCalendar=Fri 18:00:00

The weekdays must be in English and you can either use the three letter abbreviated form or the long version.

To trigger a task every five minutes starting at 00:00

OnCalendar=*:0/5

The asterisk means every day, every five minutes starting from the minute 0.

To set “turn on” times for your digital picture frame during weekdays, you could use

OnCalendar=Mon..Fri 07:00:00

This task will then be executed at 7 o’ clock in the morning from Monday to Friday.

And if you want to go wild, and define a certain image playlist or directory for your wedding anniversary every year (so you don’t forget it), you can create a timer that is triggered only once a year, like

OnCalendar=*-5-1, 06:00:00

This schedules a task on May 1 of every year, at 6am.

You can make all kinds of combinations and exception much more flexibly than you ever could with crontab.

Useful timer commands

List all timers

To list all active timers on your Raspberry Pi system type

systemctl list-timers

If you add the --all option at the end, you will see a list of all timers, active or not, which is helpful for debugging.

The output shows you

  • NEXT: The next time the timer will run
  • LEFT: How many times before the next time timer will run again
  • LAST: The last time the timer ran
  • PASSED: How much time has passed since the last time the timer ran
  • UNIT: The timer unit in which the schedule is set
  • ACTIVATES: The service unit activated by the timer

Activate a timer now

Activating a timer ad hoc is done with

$ sudo systemctl start <timer-unit-name>.timer

To have a timer automatically activated at boot, make sure it has an [Install] paragraph, where you specify when the activation should happen, like e.g., WantedBy=timers.target.

Stopping a timer now

To stop it again, type

$ sudo systemctl stop <timer-unit-name>.timer

Automatically start at boot

To automatically start a timer when booting use

$ sudo systemctl enable <timer-unit-name>.timer

and disable to remove this autostart again.

Only enable and start the timer unit, not the service unit.

Whenever you edit the unit files enter

$ sudo systemctl daemon-reload

Check the timer status

Of course, there is also a status check with

$ sudo systemctl status <timer-unit-name>.timer

which shows you exactly when the timer will trigger next.

Example .service and .timer combination to turn your frame on/off at fixed times

One of the simplest use cases for a timer is a script that turns your frame on in the morning and off when you go to sleep. And as workdays are different from weekends, you need to specify that, too.

The command to turn your screen on is

sudo vcgencmd display_power 1

and to turn it off

sudo vcgencmd display_power 0

Let’s build a .service file which turns it on:

Create a new file with

sudo nano /etc/systemd/system/turn_monitor_on.service

Copy & paste

[Unit]
Description=Turns the monitor on

[Service]
User=pi
ExecStart=sudo vcgencmd display_power 1

[Install]
WantedBy=multi-user.target

and save the file with CTRL+O and close the editor with with CTRL+X.

Create the corresponding .timer file with

sudo nano /etc/systemd/system/turn_monitor_on.timer

Copy & paste

[Unit]
Description=Timer to turn the monitor on

[Timer]
OnCalendar=Mon..Fri 07:00
OnCalendar=Sat,Sun 09:00

[Install]
WantedBy=timers.target

and save the file with CTRL+O and close the editor with with CTRL+X.

We need to change the file permissions to make the files readable by all by typing

sudo chmod 644 /etc/systemd/system/turn_monitor_on.service

Tell the system that you have added this file and want to enable this service so that it starts at boot.

sudo systemctl daemon-reload
sudo systemctl enable turn_monitor_on.timer

Do not enable the service file because that would mean to start the service at boot time independent of any timer settings.

Now create almost the same service and timer for turning the screen off at night.

Reboot your Pi, and you are all set!

To check if everything is ok, type

systemctl list-timers

Conclusion

The timer command of systemd gives you plenty of flexibility to schedule events very precisely by date or time. Although it is a bit more complex than crontab, it provides plenty of variations that can be specified and verified in (more or less) plain English.

That’s why I have abandoned good old crontab, which has served me loyally over all these years in favor of the younger systemd services and timer. Please don’t make me feel bad. It’s only software!

Was this article helpful?


Thank you for your support and motivation.


Scroll to Top