#!/usr/bin/perl # # Shutdownscript extb-poweroff.pl for extb-Board # # adapt by Andreas Brachold <vdr04-at-deltab.de> # based on Shutdownscript for ACPI by Thomas Koch <tom-at-linvdr.org> # use strict; use POSIX qw(strftime sprintf localtime time); use Time::Local; ################################################################################ # Our readed config file, to overload the default values my $CONFIGFILE = "/etc/extb/extb-poweroff.conf"; ################################################################################ ### Defaultvalues, for adjust you can use /etc/extb/extb-poweroff.conf ######### ################################################################################ my %Config; # How many Seconds should poweron before timer started $Config{"STARTUPMARGIN"} = 300; # How many second need your system for Shutdown, extb-timer run not until power is down $Config{"SHUTDOWNDURATION"} = 15; # How many seconds can drift the timer on one day $Config{"DAILYOFFSET"} = 0; # Wake avery night at 02:00 for e.g. EPG Scan $Config{"WAKEFOREPGSCAN"} = 0; # if you wish to use external script to stop shutdown, maybe adjust name $Config{"CHECKSCRIPT"} = ""; # Send Macro before Shutdown "" for nothing, "M2" for $Config{"RCSEND_VIDEOOFF"} = ""; # shutdown command, on small system like LINVDR use "/bin/busybox poweroff" $Config{"SHUTDOWN"} = "/sbin/shutdown -h now"; # Which command should call to transfer IR Codes to extb-board rc or irsend $Config{"RCCMD"} = "/usr/bin/rc"; # required commando to send messages to VDR, maybe adjust path $Config{"SVDRSEND_PL"} = "/usr/bin/svdrpsend.pl"; # Should set hardware clock through ext-poweroff.pl, set it to "hwclock -w" $Config{"SETCLOCK"} = ""; ################################################################################ # Internal Limits and change only if you know what you do # How long should extb sleep, eg only 1 Day, 1 Week , 1 Month ... if used timer delay bigger my $SLEEPLIMIT = 0xFFFFFF; # FFFFFF are 2^24 * 0.524288 Sek = 8.796.093 Sek = 146.601 Min = 101,8 Days # Duration of one counter step inside the PIC, 4MHz are 0.524288 sek my $PICTICKER = 0.524288; # Dump any messages on Screen and don't go powerdown my $DEBUG = 0; ################################################################################ my ($STARTUPMARGIN,$SHUTDOWNDURATION,$DAILYOFFSET,$WAKEFOREPGSCAN,$CHECKSCRIPT); my ($RCSEND_VIDEOOFF,$SHUTDOWN,$RCCMD,$SVDRSEND_PL,$SETCLOCK); ################################################################################ # Dump some Debugmessages sub dprint { $_ = join("", @_); chomp; print "$_\n" if($DEBUG); } ################################################################################ # Run external user script sub CheckScript { if ($CHECKSCRIPT && -x $CHECKSCRIPT) { my($Next, $Delta, $Channel, $Recording, $UserShutdown) = @ARGV; my $msg = `$CHECKSCRIPT $Next $Delta $Channel \"$Recording\" $UserShutdown`; if($msg) { SendMsg($msg); dprint("Shutdown canceld"); exit 1; } } } ################################################################################ # Execute external command sub ExecCmd { my $cmd = shift; dprint("Exec: ".$cmd); system( $cmd ) if(!$DEBUG); } ################################################################################ # send message to VDR sub SendMsg { my $msg = shift; dprint("SendMsg: ".$msg); # Hmm, nix funktioniert ... #`$SVDRSEND_PL MESG $msg &> /dev/null`; #`echo -e "MESG $msg\nQUIT" | nc 127.0.0.1 2001 &> /dev/null`; # nur per atd geht es ... `echo '$SVDRSEND_PL MESG "$msg" &> /dev/null' | at now &> /dev/null`; } ################################################################################ # Turn Video off, or send other RC Code to extb-board sub VideoOff { if($RCSEND_VIDEOOFF) { ExecCmd( sprintf("%s send_once EXTB_TX %s",$RCCMD, $RCSEND_VIDEOOFF)); } } ################################################################################ # Set clock, if your need it sub setTime { if($SETCLOCK) { ExecCmd($SETCLOCK); } } ################################################################################ # Set Alarm, your will need it ;-) sub setAlarm { my $Next = shift; setTime(); dprint("Next event at ", strftime("%d.%m.%Y %H:%M:%S", localtime($Next))); dprint("Programming wakeup at ", strftime("%d.%m.%Y %H:%M:%S", localtime($Next-$STARTUPMARGIN))); # Get difference between now and next timer my $delta = (($Next - ($STARTUPMARGIN + $SHUTDOWNDURATION)) - time()); if($delta < $STARTUPMARGIN) { SendMsg("Weckzeit zu kurz ".$delta." Sekunden"); dprint("Shutdown canceld"); exit 1; } VideoOff(); dprint("Wakeup at ",int($delta), " Seconds"); # Adjust drift crystal with 6 Sec on one day if( $DAILYOFFSET > 0) { $delta -= ($delta / 86400)*$DAILYOFFSET; # 24h*60m*60s dprint("Adjusted Wakeup at ",int($delta), " Seconds"); } # Adjust for PIC Counterticks my $valueint = $delta / $PICTICKER; dprint("PIC value ", int($valueint), " PicTics"); # Userclipping if(int($valueint) > $SLEEPLIMIT){ $valueint = $SLEEPLIMIT; } # Systemclipping if(int($valueint) > 0xFFFFFF) { $valueint = 0xFFFFFF; } # integer to hex ( 6 Characters) my $valuehex = uc(sprintf("%06x",int($valueint))); # insert between all hex character a placeholder "space" my $valuestring = ""; for(my $i = 0; $i <= length($valuehex); $i+=1){ $valuestring = $valuestring.substr($valuehex,$i,1)." "; }; # Execute rc to send new timer ExecCmd( sprintf("%s send_once EXTB_TX %s",$RCCMD,$valuestring )); } ################################################################################ # Execute System shutdown sub PowerOff { ExecCmd( $SHUTDOWN ); exit 0; } ################################################################################ # Get time from next day at 02:00 sub NextTwoOclock { my $now = time(); # Array-Format: ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) my @today = localtime($now); @today[0..2] = (0, 0, 2); # get today 2:00 in seconds since epoc my $TwoOclock = timelocal(@today); # Check: Is today 2:00 in future or past? if($now < $TwoOclock) { # Today two oclock is in future return $TwoOclock; } else { # We're past two oclock, next two oclock is tomorrow (+86400s) return $TwoOclock+86400; } } ################################################################################ # lookup for configuration file if ($CONFIGFILE && -e $CONFIGFILE) { open(CONFIG, "< $CONFIGFILE") or die "can't open $CONFIGFILE: $!"; while (<CONFIG>) { chomp; # no newline s/#.*//; # no comments s/^\s+//; # no leading white s/\s+$//; # no trailing white next unless length; # anything left? my ($var, $value) = split(/\s*=\s*/, $_, 2); $Config{$var} = $value; dprint("Config{\"$var\"} = ".$value); } } ################################################################################ # Set readed or default configuration $STARTUPMARGIN = $Config{"STARTUPMARGIN"}; $SHUTDOWNDURATION = $Config{"SHUTDOWNDURATION"}; $DAILYOFFSET = $Config{"DAILYOFFSET"}; $WAKEFOREPGSCAN = $Config{"WAKEFOREPGSCAN"}; $CHECKSCRIPT = $Config{"CHECKSCRIPT"}; $RCSEND_VIDEOOFF = $Config{"RCSEND_VIDEOOFF"}; $SHUTDOWN = $Config{"SHUTDOWN"}; $RCCMD = $Config{"RCCMD"}; $SVDRSEND_PL = $Config{"SVDRSEND_PL"}; $SETCLOCK = $Config{"SETCLOCK"}; ################################################################################ # Main task # my $TwoOclock = NextTwoOclock(); if(scalar(@ARGV)) { # called from vdr die "Wrong parameter count\n" if(scalar(@ARGV) != 5); CheckScript(); my($Next, $Delta, $Channel, $Recording, $UserShutdown) = @ARGV; # dprint ("$Next, $Delta, $Channel, $Recording, $UserShutdown"); # find out: Next start at 2:00 or at next timer? if(($Next) && (!($WAKEFOREPGSCAN) || ($Next < $TwoOclock))) { setAlarm($Next); } else { if($WAKEFOREPGSCAN) { setAlarm($TwoOclock); } else { VideoOff(); } } PowerOff(); } else { # called from cmdline my $next = `$SVDRSEND_PL next abs`; if($next =~ /550 No active timers/) { if($WAKEFOREPGSCAN) { # start every day at 2:00 local time for EPG update & Co. setAlarm($TwoOclock); } else { VideoOff(); } PowerOff(); } elsif($next =~ /250 \d+ (\d+)/) { # find out: Next start at 2:00 or at next timer? if(($1 < $TwoOclock) || !($WAKEFOREPGSCAN)) { setAlarm($1); } else { if($WAKEFOREPGSCAN) { setAlarm($TwoOclock); } else { VideoOff(); } } PowerOff(); } else { print "HELP! What to do? ($next)\n"; } exit 1; }