Powersave, auto shutdown and auto startup

Added by Dutchy Nl 10 months ago

To auto-shutdown and auto-startup a computer which only serves as a TvHeadend-server, the next script might be of some help.
It 's the result of copying, pasting and some additional tweaking of already existing scripts on this site.

The script checks for:
  • active clients in the network (actual and/or potential viewers)
  • active users on the server
  • upcoming recordings in a given period of time in which it 's not very useful to shut down and start up again (default 10 mins)
  • actual recordings

In case no clients, no users and/or no (almost) active recordings are detected then a shutdown signal will be sent after setting the wakeup-timer for the next recording.
Default wakeup will be set to 3 mins prior the next recording (extra time according to TvHeadend settings included).
Which gives the computer 3 mins to start up.
Example: program will start at 10:00, start ahead TvHeadend 5 mins, so wakeup is at 9:52 and recording can start at 9:55.

Be sure the RTC is set (and stays set) to UTC-time.
Also be sure that the user who calls the script has rights to execute (see the wiki about “HowTo wakeup XBMC/TVHeadend for scheduled recording”).

Detection of active clients is default set to “off”, because IP-addresses to be checked must be filled out first (see the second “CHECK THIS” section for details).

Finally: run the script with "sudo”-rights each 5 minutes (or so) as a cronjob (crontab -e).
Running the script as a post_recording command from inside TvHeadend isn't very useful, because in case shutdown is blocked, the computer will stay on forever or at least until the end of the next recording.
The script checks only once and not permanently.

Enjoy!

--- the script --------------------------------------------------------------------------------

#!/bin/bash

# prevent this script from running during boot
sleep 150s

# set directory
cd ~hts/.hts/tvheadend/dvr/log

# some initial values
start_date=0
recording=0
current_date=`date +%s`
wake_date=$((current_date+172800))
clientA=0
clientB=0
clientC=0
clientD=0
clientE=0
clientF=0
clientG=0
clientH=0
clientI=0
clientJ=0
users_count=0

# start CHECK THIS start
# set time NOT to shut down before next recording
# minimum time in seconds needed for consecutive shutdown AND startup
safe_margin_start=600
# set time to start up before next recording
# minimum time in seconds needed to start up the computer properly
safe_margin_startup=180
# end CHECK THIS end

# routine to find out start and stop running recording and next recording
for i in $( ls ); do
tmp_start=`cat $i | grep '"start":' | cut -f 2 -d " " | cut -f 1 -d ","`
tmp_stop=`cat $i | grep '"stop":' | cut -f 2 -d " " | cut -f 1 -d ","`
tmp_start_extra=$((`cat $i | grep '"start_extra":' | cut -f 2 -d " " | cut -f 1 -d ","`*60))
tmp_stop_extra=$((`cat $i | grep '"stop_extra":' | cut -f 2 -d " " | cut -f 1 -d ","`*60))

# check for any running or almost running recording
if [ $((tmp_stop+tmp_stop_extra)) -gt $((current_date)) -a $((tmp_start-tmp_start_extra-safe_margin_start)) -lt $((current_date)) ]; then
recording=1
fi

# check for next recording and set wake up time
if [ $((tmp_stop+tmp_stop_extra)) -gt $((current_date)) -a $((tmp_start-tmp_start_extra-safe_margin_start)) -gt $((current_date)) ]; then
# take lower value (tmp_start or start_date)
if [ $((start_date)) -eq 0 -o $((tmp_start-tmp_start_extra-safe_margin_start)) -lt $((start_date)) ]; then
start_date=$((tmp_start-tmp_start_extra-safe_margin_start))
wake_date=$((tmp_start-tmp_start_extra-safe_margin_startup))
program_date=$((tmp_start))
fi
fi

done

# set wakeup time
if [ $((start_date)) -ne 0 ]; then
echo 0 > /sys/class/rtc/rtc0/wakealarm
echo $wake_date > /sys/class/rtc/rtc0/wakealarm
fi

# start CHECK THIS start
# check for active clients
# this will only work properly with static ip-addresses and remember to exclude your tvheadend-server
# uncomment up to next 10 lines and fill out the ip-addresses to be checked
# clientA=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientB=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientC=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientD=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientE=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientF=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientG=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientH=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientI=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientJ=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
clients_count=$((clientA+clientB+clientC+clientD+clientE+clientF+clientG+clientH+clientI+clientJ))
# end CHECK THIS end

# start CHECK THIS start
# check for active users
users_count=$(who | wc -l)
# end CHECK THIS end

# reports after running the script manually

# about clients
if [ $((clients_count)) -ne 0 ]; then
echo "Active clients detected" 
else
echo "No clients detected" 
fi 

# about users
if [ $((users_count)) -ne 0 ]; then
echo "Active users detected" 
else
echo "No users detected" 
fi 

# about recording
if [ $((recording)) -ne 0 ]; then
echo "Recording in progress" 
else
echo "Not recording" 
fi

# about time
echo "Start up @ `date -d @$wake_date +"%T %d.%m.%Y"`" 
echo "Next recording @ `date -d @$((wake_date+safe_margin_startup)) +"%T %d.%m.%Y"`" 
echo "Next program @ `date -d @$((program_date)) +"%T %d.%m.%Y"`" 

# end of reports

# final check no-client-present  no-user-present no-active-recording no-upcoming-recording-within-safe_margin_start will result in shutdown
sleep 10s
if [ $((clients_count)) -eq 0 -a $((users_count)) -eq 0 -a $((recording)) -eq 0 ]; then
sudo shutdown -h now
fi

Replies (18)

RE: Auto shutdown and auto startup - Added by Hein Rigolo 10 months ago

I just came across this script ....

Did you know about this page:
http://tvheadend:9981/status.xml

I think most of the information that you are now "grabbing" from the logs is also contained in that xml output.

Hein

RE: Auto shutdown and auto startup - Added by mike hussy 10 months ago

Such posts should be updated and shared frequently on the web, unlike the pictures and videos which are only marketing material, these posts are really valuable to a reader.

RE: Auto shutdown and auto startup - Added by Dutchy Nl 10 months ago

"Did you know about this page: http://tvheadend:9981/status.xml"

No I didn't. Found it after some searching on the server.
It's a standard feature of TvHeadend?
Might help making the script more simple and faster.

RE: Auto shutdown and auto startup - Added by Richard Lloyd 9 months ago

I have a similar script myself, although I used the rtcwake command rather than echoing into the /proc filesystem,
so the system isn't actually shut down, but actually suspended instead. However, when it wakes again, the
TBS drivers aren't in a good state (yes, I've tried stopping tvheadend and unloading kernel modules prior to
a suspend and doing the reverse when it wakes, but it still doesn't init the TBS drivers properly). In the end,
my script has an option to reboot after a wake, which is what I'm currently using.

Of course, this sort of shutdown/wake script also needs to be accompanied by some Wake ON LAN code when you
boot any of the media centre clients. I run mine from /etc/rc.local. If you don't do this, tvheadend
probably won't be available for viewing past recordings or setting new recordings etc.

Also, what's really, really annoying about XBMC and its tvheadend PVR client is that if tvheadend isn't available
when you start XBMC, it will not re-poll periodically to see if it has appeared on the network and the whole Live TV
stuff just sits there doing nothing, even if tvheadend is started after XBMC. Only a restart of XBMC after firing up
tvheadend works, which hit me so many times that I put a Wake On LAN (and delay) wrapper on the XBMC icon on my
Ubuntu desktop so that when it clicks, it will pause until tvheadend is available and only then fire up XBMC.

Oh and shouldn't tvheadend do all this anyway? - Added by Richard Lloyd 9 months ago

Actually, I wish tvheadend had suspend/wake functionality built into its own code,
rather than people having to hack up their own scripts. There should be a bunch of config
options with it like:

  • Shutdown or suspend when idle (the latter will not reboot on a wake) - this could be a privileged
    operation so I'm not sure if some sort of setuid'ed-to-root wrapper might be needed here. The suspend option may need
    the ability to unload a set of listed modules at suspend time and then reload them (in the right order!) at resumption,
    assuming the tuner drivers can survive this OK of course.
  • Don't shutdown/suspend if active (Web serving, playback or recording in operation or someone ssh'ed into the tvheadend
    server). It's easy for an external script to find if a recording is in progress (my script and the one posted here just look through the logs or xml),
    but I suspect it's a lot harder for an external script to know if any client is using tvheadend (Web browsing, streaming or recording playback
    occurred in the last few minutes).
  • Choose the idle time that triggers suspend/shutdown - should be a minimum of 1 minute to allow any recordings to
    be flushed to hard disk by the OS. The resumption should occur at (next recording time - pre-padding - idle time). Don't
    suspend/shutdown if the current time is >= resumption time of course, though I personally added another 10 minutes to my
    script because I didn't want a shutdown, only possibly have to boot again 10 minutes later.

RE: Oh and shouldn't tvheadend do all this anyway? - Added by Eric Valette 8 months ago

Richard Lloyd wrote:

Actually, I wish tvheadend had suspend/wake functionality built into its own code,
rather than people having to hack up their own scripts. There should be a bunch of config
options with it like:

The problem is that you may want to wake up for many other reasons and other program may decide that from their own viewpoint its time to sleep. So it must be global.

-- eric

RE: Auto shutdown and auto startup - Added by Adam Sutton 8 months ago

I completely agree with Eric, power management (suspend/resume/whatever) should be the realm of a power manager. It's very rare that Tvheadend be installed in a single application environment (by that I mean TVH is the only service provided by a server), and therefore as Eric points out there will be other services that have differing requirements for when a system should suspend/resume.

For a long time I used to use powernap on my Ubuntu Server and had intended to write a plugin for it to hook into my tvheadend recordings. It would have been a relatively trivial thing to do. Unfortunately due to changes in my usage and reduced power consumption of my server I don't bother to suspend anymore so no longer use powernap.

But certainly I think that sort of solution is a much better one than having TVH do the power management internally since very few people would want to use it anyway. That being said some improvements to make TVH work better in a suspend/resume setup would be good.

Adam

RE: Auto shutdown and auto startup - Added by Eric Valette 8 months ago

On my side I use a heavily hacked version of sleepd (unmaintained still use APM instead of ACPI, ...) that I fine tuned for NAS power save function but I'm still missing the wakeup side. I considered writing a small programmed wakeup database myself but did not manage to find time so far. Plus it would need in addition to a network interface, a GUI and I'm totally novice at GUI apps writing. typically the waleup database could be populated but the recording database automatically...

RE: Powersave, auto shutdown and auto startup - Added by Peter Betts 5 months ago

This sounds exactly what I need.

I have an old PC running TVheadend and it works really well. So quick to boot up and works faultlessly, giving a great picture through XBMC.

I really want to move to TVheadend for my recording as well as viewing, but I would need the PC to shutdown and wake it self up to make recordings.

This script sounds perfect for me. I'm not very good on Linux, but I have created a file with the above script (signed on as root).
I've tried to run it manually to see if it works ok, but I get the following error :

/root/shutty: line 48: syntax error near unexpected token `fi'
/root/shutty: line 48: `fi'

I called the file shutty and just put it in the root folder

Anyone any ideas what I've done wrong?

RE: Powersave, auto shutdown and auto startup - Added by Peter Betts 5 months ago

Hi,

Line 48 is just fi and is preceded by :

  1. check for any running or almost running recording
    if [ $((tmp_stop+tmp_stop_extra)) -gt $((current_date)) -a
  2. $((tmp_start-tmp_start_extra-safe_margin_start)) -lt $((current_date)) ];
  3. then
    recording=1
    fi <----- Line 48

I understand the fi is an "end of script" line, but I don't understand the error.

Thanks

RE: Powersave, auto shutdown and auto startup - Added by Dutchy Nl 5 months ago

If line 48 is "fi"
Then:
- Line 47 should be "recording=1"
- And line 46 should be "if [ $((tmp_stop+tmp_stop_extra)) -gt $((current_date)) -a $((tmp_start-tmp_start_extra-safe_margin_start)) -lt $((current_date)) ]; then"

It looks like you have cut line 46 in 3 pieces.

RE: Powersave, auto shutdown and auto startup - Added by Peter Betts 5 months ago

Thanks Dutchy,

You're completely correct, I had messed up line 46. I changed it and manually run it with no problems.

I've added it to a cronjob and its just switched itself off. Many thanks for your help, and thanks for sharing the script.

Pete.

RE: Powersave, auto shutdown and auto startup - Added by Richard Lloyd 5 months ago

In reply to the early post by Hein - you do realise that the XML page is password protected and any cron'ed script would have to pass the username and password in the clear to it? Makes it less than useful as a data source, IMHO.

Anyway, I thought I'd post up my equivalent of Dutchy's script called "suspend_if_idle" that I've been using all this year without issue. It does require the more "official" way of timer-based suspension using the rtcwake binary (found in the utils-linux package on Debian/Ubuntu for example) and has a little more functionality than Dutchy's script such as:

  • Comprehensive logging including time and date.
  • Will start tvheadend if it's not running and then use the running process to find its user (and its home dir for the logs).
  • Three modes of operation that you can pick depending on your setup:
    - Suspend/wake only.
    - Stop tvheadend/unload tuner modules/suspend/wake/reload tuner modules/start tvheadend.
    - Suspend/wake/reboot (I have to use this mode with my TBS cards!).
  • Ability to suspend "indefnitely" (a year in fact) if server is idle and no future recordings are scheduled.

If someone can use this script as a starting point to find a way to suspend/wake TBS cards without a reboot, that would be great...

suspend_if_idle (8.68 KB)

RE: Powersave, auto shutdown and auto startup - Added by Dutchy Nl 5 months ago

Thanks for your post Richard.
The ".... suspend "indefinitely" (a year in fact) ..." triggered me. (Thanks :-)
The TvHeadend server should run at least each two days or so to refresh the automatic recorder schedule.
Just because the EPG info covers only two/three (max six) days in the future.
Inserting a new line behind line 10 will solve this (added to the originally posted script) "wake_date=$((current_date+172800))".

RE: Powersave, auto shutdown and auto startup - Added by Richard Lloyd 5 months ago

Yes, suspending for a year is probably overkill, but I guess I assumed that you'd either set some manual recordings for any holidays where you'd leave it unattended for a week or more or you'd be running the client regularly enough to wake on LAN the server and pick up any new EPG/auto recordings you needed. I would suspect the maximum "forever" time is how in advance your EPG is. For the UK Radio Times feed, that's around 14 days, so that's a figure I probably should have used, though it can't harm to have it shorter than that (I wouldn't put it less than 7 days myself though, since surely every EPG data set is at least that length?).

I'm not sure why you picked 2 days - surely any auto recordings would be set right through any EPG data you've got, so it's the EPG data that determines the maximum suspend time, not the arbitrary 2 days (unless that is your EPG data period!).

I still wish tvheadend would do something to help towards the concept of suspending/waking a tvheadend server. I know people have said "but other stuff could be using the system", but that's why scripts like the ones posted here do actually check for interactive sessions or the pinging of clients on the LAN (in anticipation of them needing to use the server at any time) and don't suspend if any are present.

I know Adam has said that tvheadend wasn't designed to be restarted (particularly mid-recording!), but that's something suspend/wake may well do (I have to reboot after a wake, so tvheadend can be restarted several times a day). I think tvheandend should cope gracefully with restarts at any time - its current issues with that include always starting the XML grabber despite the elapsed interval not being reached (i.e. it doesn't checkpoint the last grab time in a temporary file, which it would need to do) and creating multi-part recordings of a single programme if restarted in mid-recording and then promptly ignoring all but the latest part on playback or deletion.

I do think there should be a tvheadend config option where you can run a custom script when the tvheadend server is "idle" (where idle = something like the checks done by the scripts here). The only snag is that it would have to be privileged, so maybe a C version of the shell script is in order to make it more conducive to being run by tvheandend? The tvheadend check is much more efficient that having to run a cron job regularly, IMHO.

RE: Powersave, auto shutdown and auto startup - Added by Dutchy Nl 5 months ago

The "arbitrary" two days is indeed the reliable (!) EPG data period (over the air, NL).
The full EPG data period is a little longer than three days, but the data after two days shows lots of schedule gaps and/or other errors.
Brings up the idea of modifying the script to wake-up the server 2 days after the last shutdown at the latest, even if there is a recording scheduled past the 2 days period.

On my server the script runs every 5 minutes.
Which means the server shuts down 5 mins after wake-up after a two day period without any recording.
A cold start takes max 75 seconds, which results in 3 mins and 45 secs for updating EPG data and scheduling (eventually) a new recording.
That should do and won't lead to bankruptcy because of extremely high electricity bills.

A wake-up after suspend takes about 30 secs, but doesn't result - similar to your case, Richard - in a properly working system.
Some necessary modprobes take about 15 to 20 secs, but also won't always - for granted - result in a stable system.
Therefore a full shutdown followed by a normal boot is preferred over resume-after-suspend.
The 25 secs extra, needed for a cold start, resulting in a stable running system, won't harm the FAF/GAF/WAF (family/girlfriend/wife acceptance factor :-), since a stable system prevails over 25 secs less waiting time.

RE: Powersave, auto shutdown and auto startup - Added by Dutchy Nl 5 months ago

New version of the script including the above mentioned adjustments and modifications, plus a check on running post recording processes.

#!/bin/bash

# set directory
cd ~hts/.hts/tvheadend/dvr/log

# start CHECK THIS section

# set time in seconds to prevent this script from running during boot
sleep 150s

# set time NOT to shut down before next recording
# minimum time in seconds needed for consecutive shutdown AND startup
safe_margin_shutdown=600

# set time to start up before next recording
# minimum time in seconds needed to start up the computer properly
safe_margin_startup=180

# set maximum hours EPG data available needed for updating automatic recorder schedule
# equivalent to maximum period system will not wake up if no future recording is detected
epg_hours=48

# set check for active users
# initial number of active users do-not-change
user_count=0
# uncomment next line to enable 
user_count=$(who | wc -l)

# set check for active clients
# this will only work properly with static ip-addresses and remember to exclude your tvheadend-server
# initial status clients do-not-change
clientA=0
clientB=0
clientC=0
clientD=0
clientE=0
clientF=0
clientG=0
clientH=0
clientI=0
clientJ=0
# uncomment up to next 10 lines and fill out the ip-addresses to be checked
# clientA=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientB=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientC=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientD=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientE=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientF=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientG=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientH=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientI=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')
# clientJ=$(ping -c1 192.168.X.X | grep 'received' | awk -F ',' '{print $2}' | awk '{ print $1}')

# set check for active post recording processes
# initial status processes do-not-change
processA=0
processB=0
processC=0
processD=0
processE=0
processF=0
processG=0
processH=0
processI=0
processJ=0
# uncomment up to next 10 lines and fill out the names of the processes to be checked
# processA=$(ps -A | grep 'process id' | wc -l)
# processB=$(ps -A | grep 'process id' | wc -l)
# processC=$(ps -A | grep 'process id' | wc -l)
# processD=$(ps -A | grep 'process id' | wc -l)
# processE=$(ps -A | grep 'process id' | wc -l)
# processF=$(ps -A | grep 'process id' | wc -l)
# processG=$(ps -A | grep 'process id' | wc -l)
# processH=$(ps -A | grep 'process id' | wc -l)
# processI=$(ps -A | grep 'process id' | wc -l)
# processJ=$(ps -A | grep 'process id' | wc -l)

# end CHECK THIS section

# some other initial values do-not-change
recording=0
current_date=`date +%s`
epg_secs=$((epg_hours*3600))
wake_date=$((current_date+epg_secs))

# routine to find out start and stop active recording and next recording
for i in $( ls ); do

# retrieve and calculate wake up data
program_start=`cat $i | grep '"start":' | cut -f 2 -d " " | cut -f 1 -d ","`
program_stop=`cat $i | grep '"stop":' | cut -f 2 -d " " | cut -f 1 -d ","`
recording_start_extra=$((`cat $i | grep '"start_extra":' | cut -f 2 -d " " | cut -f 1 -d ","`*60))
recording_stop_extra=$((`cat $i | grep '"stop_extra":' | cut -f 2 -d " " | cut -f 1 -d ","`*60))
shutdown_prevent=$((program_start-recording_start_extra-safe_margin_shutdown))
recording_end=$((program_stop+recording_stop_extra))
wake_date_tmp=$((program_start-recording_start_extra-safe_margin_startup))

# check for any running recording
if [ $((recording_end)) -gt $((current_date)) -a $((shutdown_prevent)) -lt $((current_date)) ]; then
recording=1
fi

# check for next recording and set wake up time
if [ $((wake_date_tmp)) -gt $((current_date)) -a $((wake_date_tmp)) -lt $((wake_date)) ]; then
wake_date=$((wake_date_tmp))
fi

done

# set wake up time
echo 0 > /sys/class/rtc/rtc0/wakealarm
echo $wake_date > /sys/class/rtc/rtc0/wakealarm

# check for active clients
client_count=$((clientA+clientB+clientC+clientD+clientE+clientF+clientG+clientH+clientI+clientJ))

# check for active post recording processes
process_count=$((processA+processB+processC+processD+processE+processF+processG+processH+processI+processJ))

# REPORTS after running the script manually

# about clients
if [ $((client_count)) -ne 0 ]; then
echo "Active clients detected" 
else
echo "No clients detected" 
fi 

# about users
if [ $((user_count)) -ne 0 ]; then
echo "Active users detected" 
else
echo "No users detected" 
fi 

# about recording
if [ $((recording)) -ne 0 ]; then
echo "Recording in progress" 
else
echo "Not recording" 
fi

# about processes
if [ $((process_count)) -ne 0 ]; then
echo "Active post recording processes detected" 
else
echo "No post recording processes detected" 
fi 

# about time
echo "Next wake-up @ `date -d @$wake_date +"%T %d.%m.%Y"`" 

# end of REPORTS

# final check will result in shutdown if
# no post recording processes present
# no clients present
# no users present
# no active recordings taking place
# no upcoming recording within safe_margin_shutdown detected
if [ $((process_count)) -eq 0 -a $((client_count)) -eq 0 -a $((user_count)) -eq 0 -a $((recording)) -eq 0 ]; then
sleep 10s
sudo shutdown -h now
fi

(1-18/18)