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:00monthly
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.
Related Articles
- The ultimate guide on using systemd to autostart scripts on the Raspberry Pi
- How to fix an unreliable WiFi connection on your Raspberry Pi picture frame
- How to find the IP address of a new device in your network with Angry IP Scanner
- Stay Connected: Enhancing Raspberry Pi Wi-Fi Stability by Turning Off Power Management