bin/heat: Fix missing: heat.schedule
[nethome.git] / bin / heat
index a3ac277..74bbbab 100755 (executable)
--- a/bin/heat
+++ b/bin/heat
@@ -2,6 +2,12 @@
 # * * * * * nice -n20 /root/bin/heat -s
 use strict;
 use warnings;
+my $schedulefile="/root/heat.schedule";
+my $statefile="/root/heat.state";
+my $resetfile="/root/heat.reset";
+my $usbrelay="/root/bin/usbrelay";
+my $logfile="/var/log/heat.log";
+require POSIX;
 $|=1;
 sub readfile($) {
   my($fname)=@_;
@@ -15,19 +21,22 @@ sub readfile($) {
   close F or die "read-close $fname: $!";
   return $F;
 }
-sub writefile {
-  my($fname,$content)=@_;
+sub writefile($$;$) {
+  my($fname,$content,$mode)=@_;
   local *F;
-  open F,">$fname" or die "$fname: $!";
+  open F,($mode||">").$fname or die "$fname: $!";
   print F $content or die "write $fname: $!";
   close F or die "write-close $fname: $!";
 }
+sub logmsg($) {
+  my($s)=@_;
+  chomp $s;
+  writefile $logfile,POSIX::strftime("%Y-%m-%dT%H:%M:%S",localtime)." $s\n",">>";
+}
 sub spawn($) {
   my($cmd)=@_;
   $cmd.=" >&2";
-  system $cmd or return 1;
-  warn "$cmd: $!";
-  return 0;
+  system $cmd and die "$cmd: $!";
 }
 my($trash,$min,$hour)=localtime;
 my $minutes=$hour*60+$min;
@@ -35,22 +44,23 @@ if (($ARGV[0]||"")=~/^[@]0?(\d+):0?(\d+)$/) {
   $minutes=$1*60+$2;
   shift;
 }
-my $schedulefile="/root/heat.schedule";
-my $statefile="/root/heat.state";
-my $resetfile="/root/heat.reset";
-my $usbrelay="/root/bin/usbrelay";
-my $schedule=readfile $schedulefile;
 my $finishline;
 my %schedule;
-while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) {
-  my $tm=$2*60+$3;
-  warn "$schedulefile set twice for: $1" if defined $schedule{$tm};
-  $schedule{$tm-24*60}="$1 $4\n";
-  $schedule{$tm      }="$1 $4\n";
-  $schedule{$tm+24*60}="$1 $4\n";
-}
-warn "$schedulefile garbage: $schedule" if $schedule ne "";
+my $schedule;
+if (-e $schedulefile) {
+  $schedule=readfile $schedulefile;
+  while ($schedule=~s/^(0?(\d+):0?(\d+)) ([01s])\n//) {
+    my $tm=$2*60+$3;
+    warn "$schedulefile set twice for: $1" if defined $schedule{$tm};
+    $schedule{$tm-24*60}="$1 $4\n";
+    $schedule{$tm      }="$1 $4\n";
+    $schedule{$tm+24*60}="$1 $4\n";
+  }
+  warn "$schedulefile garbage: $schedule" if $schedule ne "";
+  warn "Empty $schedulefile" if !%schedule;
+}
 sub schedulenext($) {
+  return undef if !%schedule;
   my($now)=@_;
   my($bestprev,$prev,$bestnext,$next);
   for my $found (keys(%schedule)) {
@@ -68,8 +78,10 @@ sub schedulenext($) {
   die "No bestnext" if !defined $bestnext;
   return [$prev,$next];
 }
-$finishline=schedulenext $minutes;
+$finishline=schedulenext($minutes);
+$finishline=[$finishline->[1]] if $finishline;
 my $silent=shift if ($ARGV[0]||"") eq "-s";
+logmsg "command: ".join(" ",@ARGV) if !$silent&&@ARGV;
 sub info($) {
   my($s)=@_;
   print $s if !$silent;
@@ -81,35 +93,50 @@ sub finish() {
 my $reset=readfile $resetfile if -e $resetfile;
 my($resetminutes,$resetstate);
 sub resetread() {
-  $reset=~/^0?(\d+):0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset";
+  $reset=~/^0?(\d+)[:.]0?(\d+) ([01s]|reset)\n$/ or warn "Invalid $resetfile: $reset";
   $resetminutes=$1*60+$2;
   $resetstate=($3 eq "reset"?undef:$3);
 }
+sub unlink_resetfile() {
+  unlink $resetfile or die "$resetfile: $!";
+  logmsg "remove reset: $reset";
+  $reset=$resetminutes=undef;
+}
 if (defined $reset) {
   resetread;
-  if ($resetminutes==$minutes) {
-    unlink $resetfile or die "$resetfile: $!";
-    $reset=$resetminutes=undef;
-  }
+  unlink_resetfile if $resetminutes==$minutes;
 }
 sub finishlinereset() {
   $finishline=schedulenext $resetminutes;
-  splice @$finishline,1,0,$reset;
+  if ($finishline) {
+    $finishline=[$reset,$finishline->[1]];
+  } else {
+    $finishline=[$reset];
+  }
 }
 finishlinereset if defined $reset;
 my $state=readfile $statefile;
 chomp $state;
 info $state;
 my $newstate=shift;
-$newstate=$resetstate if !defined $newstate&&defined $resetstate&&!defined $resetminutes;
+if (!defined $newstate&&defined $resetstate&&!defined $resetminutes) {
+  $newstate=$resetstate;
+  logmsg "reset: $newstate";
+}
 sub printminutes($) {
   my($m)=@_;
   return sprintf "%02d:%02d",int($m/60),$m%60;
 }
 if ($silent) {
-  if (!defined $newstate&&!defined $reset) {
-    my $prev=schedulenext($minutes)->[0];
-    $newstate=$prev if $prev=~s{^@[ printminutes $minutes ] (.)\n$}{$1} or $prev=undef;
+  if (!defined $newstate&&!defined $reset&&%schedule) {
+    my $prev=schedulenext($minutes);
+    if ($prev) {
+      my $prev=$prev->[0];
+      if ($prev=~m{^@{[ printminutes $minutes ]} (.)\n$}) {
+       $newstate=$1;
+       logmsg "scheduled: $prev";
+      }
+    }
   }
   $newstate=$state if !defined $newstate;
 }
@@ -120,12 +147,15 @@ if (!defined $newstate) {
 die "state!={s|0|1}" if $newstate!~/^[s01]$/;
 sub setstate() {
   info "->$newstate";
+  writefile $statefile,"$newstate\n" if $state ne $newstate;
+  logmsg "$state->$newstate" if $state ne $newstate;
+  if ($newstate ne "s") {
+    my $pid=readfile "pidof -x dnf;true|";
+    die "\n".printminutes($minutes)." change $state".($state eq $newstate?"":"->$newstate")." refused: dnf running: $pid" if $pid;
+  }
   my $both={"s"=>[0,0],"0"=>[1,0],"1"=>[1,1]}->{$newstate};
-  $state eq $newstate or unlink $statefile or warn "$statefile: $!";
-  (    spawn "$usbrelay 1 ".$both->[0]
-   and spawn "$usbrelay 2 ".$both->[1])
-  or do { unlink $statefile; die "usbrelay error"; };
-  $state eq $newstate or writefile $statefile,"$newstate\n";
+  spawn "$usbrelay 1 ".$both->[0];
+  spawn "$usbrelay 2 ".$both->[1];
   info "\n";
 }
 my $newreset=shift;
@@ -133,21 +163,24 @@ die "Excessive args: ".join(" ",@ARGV) if @ARGV;
 if (!defined $newreset) {
   setstate;
   if (!$silent&&defined $reset) {
-    unlink $resetfile or die "$resetfile: $!";
-    $finishline=schedulenext $minutes;
+    unlink_resetfile;
+    $finishline=schedulenext($minutes);
+    $finishline=[$finishline->[1]] if $finishline;
   }
   finish;
 }
 $reset=$newreset;
 if ($reset=~/^\d+$/) {
-  $resetminutes=$reset+$minutes;
+  $resetminutes=($reset+$minutes)%(24*60);
   $reset=printminutes($resetminutes)." reset\n";
   setstate;
 } else {
-  $reset.=" $newstate\n";
+  $reset.=" reset\n";
   resetread;
+  $reset=printminutes($resetminutes)." $newstate\n";
   info "\n";
 }
 writefile $resetfile,$reset;
+logmsg "new reset: $reset";
 finishlinereset;
 finish;