Scheduled Suspend and Resume With systemd

I recently replaced my main computer with a MacBook Pro and found myself with a spare Lenovo IdeaPad U410. Having a 32GB SSD and a 500GB HDD, I decided to set it up as a file server on my LAN.

This was all well and good, but having an always-on Intel i5 serving files I’m only likely to access during a handful of hours in the day seemed incredibly wasteful. I figured the server would only need to be on during the evenings when I’m at home, and suspended the rest of the time. I set out to automate this.

Ignoring Lid Close

The first step to automating the suspend/resume cycle is something I had already configured earlier, which is disabling automatic suspend when the lid is closed. Kind of important for a laptop server.

The way to do this with systemd (the init system we all know and love) is in /etc/systemd/logind.conf:

HandleLidSwitch=ignore

In order for this change to take effect, the logind service must be restarted:

systemctl restart systemd-logind

More information on power management with systemd can be found on the Arch Linux Wiki.

systemd Timers

systemd has a timer system that can be used to invoke systemd services similarly to cron. The OnCalendar option of timers can be used to trigger a timer at certain times according to a calendar event rule.

Suspend

In my case, I wanted to have my server suspend itself every day at 3 AM (I’m usually in bed by this time). To do this, I created /etc/systemd/system/auto-suspend.timer:

[Unit]
Description=Automatically suspend on a schedule

[Timer]
OnCalendar=*-*-* 03:00:00

[Install]
WantedBy=timers.target

By default, a timer will invoke a service by the same name when triggered, so I created /etc/systemd/system/auto-suspend.service:

[Unit]
Description=Suspend

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl suspend

The service simply runs the systemd command to suspend the computer. I imagine there might be a better way to do it, but this way works fine.

Resume

Another handy feature of systemd timers is the ability to wake the system when triggered, with the WakeSystem option. I wanted my server to resume at 6:30 PM, around the time I usually get home, so I created /etc/systemd/system/auto-resume.timer:

[Unit]
Description=Automatically resume on a schedule

[Timer]
OnCalendar=*-*-* 18:30:00
WakeSystem=true

[Install]
WantedBy=timers.target

This should do it, but the timer still wants to invoke a service, so I created a no-op in /etc/systemd/system/auto-resume.service:

[Unit]
Description=Does nothing

[Service]
Type=oneshot
ExecStart=/bin/true

Once again, there is likely a better way to achieve this, but I am no systemd expert.

(Added 2014-11-25) It was brought to my attention that unitless wake timers were suggested here, and were added to the “TODO” file here. Thanks to Alexandre Detiste for the information.

Make it Go

To turn these timers on, enable and start them:

systemctl enable auto-suspend.timer
systemctl start auto-suspend.timer

systemctl enable auto-resume.timer
systemctl start auto-resume.timer

Now my Lenovo sits on a shelf with the lid closed, only fully powered on and serving files for 8.5 hours of the day instead of 24.

Caveats

I haven’t quite figured out how to change the suspend/resume schedule on weekends, when I spend more time at home. I’m sure I just need to read a bit more on systemd Calendar Events, but it’s not the weekend yet, so I’ll worry about it later.

Update 2015-05-31:

To have different schedules on weekends and weekdays, I created two .timer files with WakeSystem=true, and prefixed the OnCalendar value of one with Mon,Tue,Wed,Thu,Fri, and the other with Sat,Sun. The same can be done for suspend. For the timers with different names, specify the unit it should invoke with Unit=auto-resume.service, for example. Remember to enable and start all timers.