Hauke’s Projects

Playin' around with Electronics and Computers

Media Center Auto Shutdown and RTC Wakeup Based on tvheadend Recording Schedule

I created a script that runs via cron job that will power off my media center if it is not in use, but will program the real time clock (RTC) on the motherboard to wake up the system in time to run a scheduled recording, and/or to update the EPG data, and from that derive potential new or changed auto-recordings. To determine if the system is currently not in use, I

  • Check if the monitor is off
  • Check if any audio is playing, e.g.,  Spotify or KODI is playing anything
  • Check if the wireless keyboard is connected
  • Check if tvheadend is currently recording something

Also, the shutdown processing can be blocked by creating a flag file. If that file exists, no shutdown will happen.

The wake-up time is either the next recording time plus some allowance for boot time, or every 24 hours, whatever comes first. This makes sure that at least once a day the EPG is updated and tvheadend can update its auto-recording-schedule.

As a result, I reduce power consumption of the media center considerably.

You may also be interested in my next blog post: CEC-like Power Features with Non-CEC-Equipment

Motivation

My brand-new x86-based Media Center is not really energy hungry, but still a bit more than my previous, Raspberry Pi 4 based incarnation. But it has a built-in RTC and the ability to wake up/boot based on an alarm programmed into that RTC. While my Raspberry Pi 4 was running 24/7 to record TV shows based on automatic recordings in tvheadend, I wanted to use the new capabilities of the new platform to improve on that and have the media center only running when needed. This will reduce power consumption way below what the old solution needed.

Concept

The general approach is to

  • create a script (decided to use a simple shell script with bash) that
  • runs regularly on a cron schedule
  • and checks if the media center is currently idle and ready for shutdown (see below)
  • and if so, determines the next wakeup time,
  • programs the RTC alarm to that wakeup time
  • and powers off the media center.
  • The RTC alarm powers the PC back on in due time.

“Idle and ready for shutdown” means:

  • Process not blocked
    By creating a given file, I can suppress the shutdown. This is to allow remote system maintenance via SSH , or to have the system up when I want to access recordings remotely via VPN, e.g., if I am travelling.
  • System is up for a minimum amount of time
    If the PC just booted, I need to give tvheadend some time to update the EPG over the air, and process it for potential new auto recordings. Therefore, after a reboot, the system will not shut down before enough time has passed.
  • Monitor is off
    If the monitor is on, this usually means that I am actively using the PC, e.g., for web browsing, watching media or listening to music. Obviously I do not want the system to shut down while I am doing that.
  • No audio is playing
    If any application is playing audio, like Spotify, KODI or the web browser, this would mean that I am listening to music, web radio or something with the monitor off. I still want the machine to keep running, for obvious reasons.
  • Wireless keyboard is not connected
    I was hoping that I could use my wireless keyboard as a very simple override-device, like having the keyboard’s power switch on to avoid any PC shutdown. Unfortunately, the wireless keyboard goes into some sleep state when no key was pressed for a while, which from the receiver side is indistinguishable from the power switch being off. Still, for a few minutes, until the keyboard goes to sleep, the mechanism will work – better than nothing. So I kept it.
  • No tvheadend recording is currently running
    Obviously I want the system to stay on until the recording is done.
    tvheadend status can be queried via API.
  • The next recording is not due in the near future
    If a recording is due within the next few minutes, do not bother to shut down and reboot.

The next wakeup time is determined with the following logic:

  • If no recording is planned, wake up in 24 hours.
  • If the next recording is scheduled in more than 24 hours, wake up in 24 hours.
  • If the next recording is scheduled in less then 24 hours, wake up at that time, minus a bit of allowance for booting.

This ensures that the PC wakes up at least every 24 hours. This is necessary to keep the EPG up to date and check if new broadcasts came up that match an auto record pattern.

Remains one caveat to be covered: Imagine playing some music with monitor off, and you need to pause output for a short while, to answer the bell or so. Now, the second after you paused output, the script runs. It would shut down the PC… Inconvenient! Solution: I require the script to decide a shutdown is due in two consecutive runs before it actually shuts down the machine. If I set the cron job to run the script every 10 minutes, I have these 10 minutes minimum as a grace period.

The resulting shell-script will follow in the end. Now follow a few things that are not 100% obvious and in some cases took me a while to work out. But first:

Credits

The starting point for this is a script shared by Mr Rooster in the tvheadend forum. Thank you very much for sharing this!

Implementation

Process System Uptime

The uptime command gives system uptime. The standard output is human readable, but difficult to interpret for the script. With uptime -s however you get the boot time in a standardised format. I convert this into a timestamp via date, and then subtract it from the current time’s timestamp. Result is the uptime in seconds.

Check if Monitor is On or Off

That was a tricky one. Many posts on the internet suggest using xrandr -q, xset -q, udevadm monitor –property or some other methods, but none worked for me. This may be due to the fact that my monitor is connected to the HDMI output of the PC via a HDMI-to-DVI-D-converter. However, even this setup offers an I²C-connection, and I finally found this post making use of this connection. It uses ddcutil detect to query the monitor, and the output will say “Invalid display” if the monitor is off, or “Display 1” if it is on (and some more information). For this to work, with Debian bookworm the following steps are necessary:

sudo apt install ddcutil

In /etc/modules-load.d/modules.conf add the line

i2c_dev

This loads the kernel-module i2c_dev at boot, which is needed by ddcutil. Now to check the monitor state is done by these lines:

This runs ddcutil detect, discards any error messages (you get some if ddcutil is not run in root context), and uses grep to check for the words “Display 1”. If the words are present, grep will return exit code 0, otherwise something non-zero (usually 1). The variable monitor_off stores this result and can be used for later checking.

Check if Any Audio is Playing

Any application that plays audio, registers an input sink with pulse audio, the audio infrastructure currently favored by Debian. If this audio sink has state “running”, it actively plays audio. So here’s how I check if audio is playing currently:

Again, I use grep to check for expected output. The output state: RUNNING is only present if a) at least one input sink is registered and b) at least one sink is actively playing back audio.

Check if the Wireless Keyboard is Connected

I use a Logitech K400 Plus (be aware of potential security issues!), and for interfacing with such keyboards, and for customizing their features, there is solaar. This software has a GUI module which allows you to interact with it nicely from the desktop, but you also can use it from the command line to gain info about the devices connected. In my case I have only one device connected, which allows me just to check for the line “device is disconnected”. If you have multiple devices connected, you may need to test more intelligently. It is really a pity that I cannot distinguish between keyboard on sleep and keyboard switched off, otherwise this would have been the perfect manual override switch…

You will need to install solaar with sudo apt install solaar. The check is quite simple and again uses the grep-logic:

Check if tvheadend is Recording Right Now

I use the tvheadend API to query the status, using the endpoint grid_upcoming. Then grep-test for the text “sched_status”:”recording”, – if it is present, a recording is in progress. Please note that you need to provide username and password if your tvheadend requires authentication.

Get Recordings and Find the Next Upcoming

I use the same endpoint to get all recordings, cut out the timestamps, sort them and pick the closest one:

Now the logic is done to determine if there’s an upcoming recording, if it is more than 24 hours in the future etc. – look into the script, it is straightforward. Note that you can configure the allowance for boot process in the variable PRE_SCHEDULE. MIN_GAP contains the time period that needs to be exceeded by the next recording in order for the shutdown to happen. If the next recording is due earlier, the PC keeps running.

Ensure a Minimum Grace Period

I found it very difficult to have my script leave a message for the next run of the same script. I was hoping I could use some environment variable, but they are well protected between shell instances. So I decided to simply write a file. If this file exists, it indicates that the last script run decided that the PC should be shut down, but did not yet do so. If the next iteration of my script is still of the opinion that the PC should be shut down and it finds the file, it actually will do the shutdown. If that next run decided that no shutdown is due anymore, it will remove the file and not do a shutdown. The flag file name can be configured in UPCOMING_SHUTDOWN_FLAGFILE.

This method is far from elegant – if you know a better way, please write a comment below!

RTC Alarm Programming and Shutdown

First, you need to ensure that the user which runs the script is allowed to sudo the necessary commands, i.e. rtcwake and poweroff, without giving a password. For this, create a file in /etc/sudoers.d – e.g., named the-user. It needs to contain this line:

the-user ALL= NOPASSWD: /usr/sbin/poweroff, /usr/sbin/rtcwake

The RTC programming command is

rtcwake -m no -t <Wakeup-Timetsamp>

-m no tells the RTC to target for “normal” state, i.e. the fully booted OS, CPU not in any sleep state. After that, the system is shut down using the poweroff command.

cron Setup

I decided to run the script every 10 minutes – for this, create a file, e.g., crontab.user, which contains the line

*/10 * * * * /home/the-user/auto_shutdown.sh

Activate this file using the command (in the relevant user’s context)

crontab crontab.user

You can check success using

crontab -l

Logging

Each run creates a logfile that you can configure in the script via variable LOGFILE. If the script decides that it will shut down the PC, it will copy the current logfile to the file configured via LASTLOGFILE variable. This allows you to check the details of the last shutdown.

Discarded Ideas

While working out this solution, I went down a few roads that turned out to be to narrow, but which I will keep here for documentation purposes. Mainly these were, instead of checking if any audio is playing, to check the following:

  • Spotify is not playing anything
    I have the Spotify fat client installed and use it to listen to music or audio plays. I may have the monitor off while I do so, but still want the system to stay on.
    Spotify play status can be queried via dbus.
  • KODI is not playing anything
    For playing back my music library, I typically use KODI. Same as with Spotify: Monitor might be off, but I want the system on.
    KODI play status can be queried via JSON-RPC API.

Check if Spotify is Currently Playing

That was surprisingly easy – an RPC call via dbus yields “Playing” or “Paused” depending on status. These lines use a similar grep-logic as with monitor on/off checking:

If Spotify is not running at all, the command will also yield a non-zero exit code, so this case is covered.

Check if KODI is Currently Playing

KODI can expose a JSON-RPC API – for this you need to go to the KODI settings, “Service” section, and under “Control” activate “Allow remote control via HTTP”. I chose to switch off authentication, since the PC runs in a well secured home network. You may want to choose a username/password, which you then would need to add to the curl command below with the option -u “username:password”.

Set up KODI HTTP access
Set up KODI HTTP access

To check if KODI plays something, you query the API for any active player, using the API-method Player.GetActivePlayers. If nothing plays, the result is empty, otherwise you get one or more player-IDs. I use sed to cut out the relevant part of the JSON response, and then the same grep logic as above:

Result and Final Words

I’m very happy to have this in place now, because I have always been very unhappy with my media center running 24/7, eating up power mostly unneeded. This script makes my media center much more eco-friendly!

You may have other requirements to determine if the PC may be shut down – I hope my examples give enough ideas and guidance for you to adjust the script to your needs.

Finally: Do not miss my next, related, blog post: CEC-like Power Features with Non-CEC-Equipment

Here’s the script – for download and as a listing (make sure to adjust the paths, and to replace the credentials for tvheadend API access):

 

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top